From e4e24f3335609b38f460ced71d18babcf11bf9cb Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Thu, 5 Dec 2024 11:18:29 +0100 Subject: Move around patches again --- patches/server/0009-MC-Utils.patch | 281 +- .../0308-Add-debug-for-sync-chunk-loads.patch | 333 + ...timise-getChunkAt-calls-for-loaded-chunks.patch | 60 - .../0309-Add-debug-for-sync-chunk-loads.patch | 333 - .../server/0309-Improve-java-version-check.patch | 36 + patches/server/0310-Add-ThrownEggHatchEvent.patch | 26 + .../server/0310-Improve-java-version-check.patch | 36 - patches/server/0311-Add-ThrownEggHatchEvent.patch | 26 - patches/server/0311-Entity-Jump-API.patch | 76 + ...option-to-nerf-pigmen-from-nether-portals.patch | 51 + patches/server/0312-Entity-Jump-API.patch | 76 - ...option-to-nerf-pigmen-from-nether-portals.patch | 51 - .../server/0313-Make-the-GUI-graph-fancier.patch | 411 + .../server/0314-Make-the-GUI-graph-fancier.patch | 411 - .../0314-add-hand-to-BlockMultiPlaceEvent.patch | 30 + ...ate-tripwire-hook-placement-before-update.patch | 18 + .../0315-add-hand-to-BlockMultiPlaceEvent.patch | 30 - ...tion-to-allow-iron-golems-to-spawn-in-air.patch | 19 + ...ate-tripwire-hook-placement-before-update.patch | 18 - ...tion-to-allow-iron-golems-to-spawn-in-air.patch | 19 - ...rable-chance-of-villager-zombie-infection.patch | 26 + ...rable-chance-of-villager-zombie-infection.patch | 26 - patches/server/0318-Optimise-Chunk-getFluid.patch | 61 + patches/server/0319-Optimise-Chunk-getFluid.patch | 61 - ...ots-verbose-world-setting-to-false-by-def.patch | 19 + .../0320-Add-tick-times-API-and-mspt-command.patch | 208 + ...ots-verbose-world-setting-to-false-by-def.patch | 19 - .../0321-Add-tick-times-API-and-mspt-command.patch | 208 - .../0321-Expose-MinecraftServer-isRunning.patch | 22 + ...0322-Add-Raw-Byte-ItemStack-Serialization.patch | 65 + .../0322-Expose-MinecraftServer-isRunning.patch | 22 - ...0323-Add-Raw-Byte-ItemStack-Serialization.patch | 65 - ...trol-spawn-settings-and-per-player-option.patch | 96 + ...trol-spawn-settings-and-per-player-option.patch | 96 - ...te-Connections-shouldn-t-hold-up-shutdown.patch | 44 + .../0325-Do-not-allow-Vexes-to-load-chunks.patch | 22 + ...te-Connections-shouldn-t-hold-up-shutdown.patch | 44 - .../0326-Do-not-allow-Vexes-to-load-chunks.patch | 22 - ...ouble-PlayerChunkMap-adds-crashing-server.patch | 47 + patches/server/0327-Don-t-tick-dead-players.patch | 21 + ...ouble-PlayerChunkMap-adds-crashing-server.patch | 47 - ...8-Dead-Player-s-shouldn-t-be-able-to-move.patch | 21 + patches/server/0328-Don-t-tick-dead-players.patch | 21 - ...9-Dead-Player-s-shouldn-t-be-able-to-move.patch | 21 - ...on-t-move-existing-players-to-world-spawn.patch | 48 + ...on-t-move-existing-players-to-world-spawn.patch | 48 - patches/server/0330-Optimize-Pathfinding.patch | 47 + patches/server/0331-Optimize-Pathfinding.patch | 47 - .../0331-Reduce-Either-Optional-allocation.patch | 48 + .../0332-Reduce-Either-Optional-allocation.patch | 48 - ...32-Reduce-memory-footprint-of-CompoundTag.patch | 50 + ...3-Prevent-opening-inventories-when-frozen.patch | 50 + ...33-Reduce-memory-footprint-of-CompoundTag.patch | 50 - ...t-run-entity-collision-code-if-not-needed.patch | 43 + ...4-Prevent-opening-inventories-when-frozen.patch | 50 - ...t-run-entity-collision-code-if-not-needed.patch | 43 - .../0335-Implement-Player-Client-Options-API.patch | 200 + ...-if-player-is-attempted-to-be-removed-fro.patch | 23 + .../0336-Implement-Player-Client-Options-API.patch | 200 - ...-if-player-is-attempted-to-be-removed-fro.patch | 23 - ...erJoinEvent-when-Player-is-actually-ready.patch | 93 + ...erJoinEvent-when-Player-is-actually-ready.patch | 93 - ...-to-spawn-point-if-spawn-in-unloaded-worl.patch | 119 + ...-Add-PlayerAttackEntityCooldownResetEvent.patch | 29 + ...-to-spawn-point-if-spawn-in-unloaded-worl.patch | 119 - ...-Add-PlayerAttackEntityCooldownResetEvent.patch | 29 - ...-Don-t-fire-BlockFade-on-worldgen-threads.patch | 27 + ...d-phantom-creative-and-insomniac-controls.patch | 43 + ...-Don-t-fire-BlockFade-on-worldgen-threads.patch | 27 - ...d-phantom-creative-and-insomniac-controls.patch | 43 - ...-Fix-item-duplication-and-teleport-issues.patch | 155 + ...-Fix-item-duplication-and-teleport-issues.patch | 155 - patches/server/0343-Villager-Restocks-API.patch | 31 + ...n-JDK-per-thread-native-byte-buffer-cache.patch | 30 + patches/server/0344-Villager-Restocks-API.patch | 31 - ...n-JDK-per-thread-native-byte-buffer-cache.patch | 30 - patches/server/0345-misc-debugging-dumps.patch | 118 + .../0346-Prevent-teleporting-dead-entities.patch | 24 + patches/server/0346-misc-debugging-dumps.patch | 118 - patches/server/0347-Implement-Mob-Goal-API.patch | 818 + .../0347-Prevent-teleporting-dead-entities.patch | 24 - .../server/0348-Add-villager-reputation-API.patch | 122 + patches/server/0348-Implement-Mob-Goal-API.patch | 801 - .../server/0349-Add-villager-reputation-API.patch | 122 - ...erienceOrb-merging-stacking-API-and-fixes.patch | 113 + ...erienceOrb-merging-stacking-API-and-fixes.patch | 113 - .../0350-Fix-PotionEffect-ignores-icon-flag.patch | 60 + .../0351-Fix-PotionEffect-ignores-icon-flag.patch | 60 - patches/server/0351-Potential-bed-API.patch | 36 + patches/server/0352-Potential-bed-API.patch | 36 - ...0352-Wait-for-Async-Tasks-during-shutdown.patch | 60 + ...tyRaider-respects-game-and-entity-rules-f.patch | 19 + ...0353-Wait-for-Async-Tasks-during-shutdown.patch | 60 - ...option-for-console-having-all-permissions.patch | 47 + ...tyRaider-respects-game-and-entity-rules-f.patch | 19 - ...option-for-console-having-all-permissions.patch | 47 - ...355-Fix-villager-trading-demand-MC-163962.patch | 20 + ...356-Fix-villager-trading-demand-MC-163962.patch | 20 - .../server/0356-Maps-shouldn-t-load-chunks.patch | 31 + .../server/0357-Maps-shouldn-t-load-chunks.patch | 31 - ...sed-lookup-for-Treasure-Maps-Fixes-lag-fr.patch | 20 + ...heduler-runTaskTimerAsynchronously-Plugin.patch | 21 + ...sed-lookup-for-Treasure-Maps-Fixes-lag-fr.patch | 20 - ...heduler-runTaskTimerAsynchronously-Plugin.patch | 21 - ...ix-piston-physics-inconsistency-MC-188840.patch | 79 + ...ix-missing-chunks-due-to-integer-overflow.patch | 29 + ...ix-piston-physics-inconsistency-MC-188840.patch | 79 - ...ix-missing-chunks-due-to-integer-overflow.patch | 29 - ...revent-position-desync-causing-tp-exploit.patch | 30 + ...y-getHolder-method-without-block-snapshot.patch | 42 + ...revent-position-desync-causing-tp-exploit.patch | 30 - .../0363-Add-PlayerRecipeBookClickEvent.patch | 65 + ...y-getHolder-method-without-block-snapshot.patch | 42 - .../0364-Add-PlayerRecipeBookClickEvent.patch | 65 - .../0364-Hide-sync-chunk-writes-behind-flag.patch | 23 + .../0365-Add-permission-for-command-blocks.patch | 79 + .../0365-Hide-sync-chunk-writes-behind-flag.patch | 23 - .../0366-Add-permission-for-command-blocks.patch | 79 - ...ntity-position-and-AABB-are-never-invalid.patch | 65 + ...ntity-position-and-AABB-are-never-invalid.patch | 65 - ...r-World-Difficulty-Remembering-Difficulty.patch | 118 + ...r-World-Difficulty-Remembering-Difficulty.patch | 118 - patches/server/0368-Paper-dumpitem-command.patch | 158 + ...prove-Legacy-Component-serialization-size.patch | 56 + patches/server/0369-Paper-dumpitem-command.patch | 158 - .../0370-Add-BlockStateMeta-clearBlockState.patch | 42 + ...prove-Legacy-Component-serialization-size.patch | 56 - .../0371-Add-BlockStateMeta-clearBlockState.patch | 42 - ...71-Convert-legacy-attributes-in-Item-Meta.patch | 44 + ...72-Convert-legacy-attributes-in-Item-Meta.patch | 44 - ...372-Do-not-accept-invalid-client-settings.patch | 24 + ...373-Do-not-accept-invalid-client-settings.patch | 24 - ...Improve-fix-EntityTargetLivingEntityEvent.patch | 35 + patches/server/0374-Add-entity-liquid-API.patch | 55 + ...Improve-fix-EntityTargetLivingEntityEvent.patch | 35 - patches/server/0375-Add-PrepareResultEvent.patch | 165 + patches/server/0375-Add-entity-liquid-API.patch | 55 - patches/server/0376-Add-PrepareResultEvent.patch | 165 - ...-chunk-for-portal-on-world-gen-entity-add.patch | 19 + ...-chunk-for-portal-on-world-gen-entity-add.patch | 19 - ...377-Fix-arrows-never-despawning-MC-125757.patch | 22 + ...378-Fix-arrows-never-despawning-MC-125757.patch | 22 - ...-Safe-Vanilla-Command-permission-checking.patch | 53 + ...T-5824-Bukkit-world-container-is-not-used.patch | 50 + ...-Safe-Vanilla-Command-permission-checking.patch | 53 - ...T-5824-Bukkit-world-container-is-not-used.patch | 50 - ...PIGOT-5885-Unable-to-disable-advancements.patch | 18 + ...mentDataPlayer-leak-due-from-quitting-ear.patch | 65 + ...PIGOT-5885-Unable-to-disable-advancements.patch | 18 - ...mentDataPlayer-leak-due-from-quitting-ear.patch | 65 - ...ptimize-NetworkManager-Exception-Handling.patch | 23 + ...0383-Fix-some-rails-connecting-improperly.patch | 84 + ...ptimize-NetworkManager-Exception-Handling.patch | 23 - ...gex-mistake-in-CB-NBT-int-deserialization.patch | 27 + ...0384-Fix-some-rails-connecting-improperly.patch | 84 - patches/server/0385-Brand-support.patch | 76 + ...gex-mistake-in-CB-NBT-int-deserialization.patch | 27 - ...d-playPickupItemAnimation-to-LivingEntity.patch | 22 + patches/server/0386-Brand-support.patch | 76 - ...d-playPickupItemAnimation-to-LivingEntity.patch | 22 - .../server/0387-Don-t-require-FACING-data.patch | 37 + .../server/0388-Don-t-require-FACING-data.patch | 37 - ...nChangeEvent-not-firing-for-all-use-cases.patch | 43 + patches/server/0389-Add-moon-phase-API.patch | 22 + ...nChangeEvent-not-firing-for-all-use-cases.patch | 43 - patches/server/0390-Add-moon-phase-API.patch | 22 - ...the-server-load-chunks-from-newer-version.patch | 40 + ...the-server-load-chunks-from-newer-version.patch | 40 - ...event-headless-pistons-from-being-created.patch | 27 + patches/server/0392-Add-BellRingEvent.patch | 25 + ...event-headless-pistons-from-being-created.patch | 27 - patches/server/0393-Add-BellRingEvent.patch | 25 - ...0393-Add-zombie-targets-turtle-egg-config.patch | 19 + ...0394-Add-zombie-targets-turtle-egg-config.patch | 19 - patches/server/0394-Buffer-joins-to-world.patch | 40 + patches/server/0395-Buffer-joins-to-world.patch | 40 - ...-colors-not-working-in-some-kick-messages.patch | 43 + patches/server/0396-Add-more-Evoker-API.patch | 38 + ...-colors-not-working-in-some-kick-messages.patch | 43 - .../0397-Add-methods-to-get-translation-keys.patch | 227 + patches/server/0397-Add-more-Evoker-API.patch | 38 - .../0398-Add-methods-to-get-translation-keys.patch | 227 - ...8-Create-HoverEvent-from-ItemStack-Entity.patch | 55 + patches/server/0399-Cache-block-data-strings.patch | 70 + ...9-Create-HoverEvent-from-ItemStack-Entity.patch | 55 - patches/server/0400-Cache-block-data-strings.patch | 70 - ...Teleportation-and-cancel-velocity-if-tele.patch | 98 + ...itional-open-container-api-to-HumanEntity.patch | 83 + ...Teleportation-and-cancel-velocity-if-tele.patch | 98 - ...itional-open-container-api-to-HumanEntity.patch | 83 - ...he-DataFixerUpper-Rewrite-Rules-on-demand.patch | 54 + ...he-DataFixerUpper-Rewrite-Rules-on-demand.patch | 54 - ...k-drop-capture-to-capture-all-items-added.patch | 43 + ...Entity-Counter-to-allow-plugins-to-use-va.patch | 38 + ...k-drop-capture-to-capture-all-items-added.patch | 43 - ...Entity-Counter-to-allow-plugins-to-use-va.patch | 38 - ...azily-track-plugin-scoreboards-by-default.patch | 76 + patches/server/0406-Entity-isTicking.patch | 36 + ...azily-track-plugin-scoreboards-by-default.patch | 76 - patches/server/0407-Entity-isTicking.patch | 36 - ...cking-non-whitelisted-player-when-white-l.patch | 27 + ...08-Fix-Concurrency-issue-in-ShufflingList.patch | 67 + ...cking-non-whitelisted-player-when-white-l.patch | 27 - ...09-Fix-Concurrency-issue-in-ShufflingList.patch | 67 - ...0409-Reset-Ender-Crystals-on-Dragon-Spawn.patch | 24 + ...ix-for-large-move-vectors-crashing-server.patch | 86 + ...0410-Reset-Ender-Crystals-on-Dragon-Spawn.patch | 24 - ...ix-for-large-move-vectors-crashing-server.patch | 86 - patches/server/0411-Optimise-getType-calls.patch | 93 + patches/server/0412-Optimise-getType-calls.patch | 93 - patches/server/0412-Villager-resetOffers.patch | 40 + ...ck-place-order-when-capturing-blockstates.patch | 24 + patches/server/0413-Villager-resetOffers.patch | 40 - ...Fix-item-locations-dropped-from-campfires.patch | 28 + ...ck-place-order-when-capturing-blockstates.patch | 24 - .../0415-Fix-bell-block-entity-memory-leak.patch | 39 + ...Fix-item-locations-dropped-from-campfires.patch | 28 - ...-bubbling-up-when-item-stack-is-empty-in-.patch | 46 + .../0416-Fix-bell-block-entity-memory-leak.patch | 39 - .../0417-Add-getOfflinePlayerIfCached-String.patch | 39 + ...-bubbling-up-when-item-stack-is-empty-in-.patch | 46 - .../0418-Add-getOfflinePlayerIfCached-String.patch | 39 - patches/server/0418-Add-ignore-discounts-API.patch | 150 + patches/server/0419-Add-ignore-discounts-API.patch | 150 - .../0419-Toggle-for-removing-existing-dragon.patch | 19 + ...420-Fix-client-lag-on-advancement-loading.patch | 35 + .../0420-Toggle-for-removing-existing-dragon.patch | 19 - ...421-Fix-client-lag-on-advancement-loading.patch | 35 - .../server/0421-Item-no-age-no-player-pickup.patch | 49 + .../0422-Beacon-API-custom-effect-ranges.patch | 131 + .../server/0422-Item-no-age-no-player-pickup.patch | 49 - patches/server/0423-Add-API-for-quit-reason.patch | 66 + .../0423-Beacon-API-custom-effect-ranges.patch | 131 - patches/server/0424-Add-API-for-quit-reason.patch | 66 - ...andering-Trader-spawn-rate-config-options.patch | 87 + patches/server/0425-Add-Destroy-Speed-API.patch | 220 + ...andering-Trader-spawn-rate-config-options.patch | 87 - patches/server/0426-Add-Destroy-Speed-API.patch | 220 - ...Player-spawnParticle-x-y-z-precision-loss.patch | 19 + .../0427-Add-LivingEntity-clearActiveItem.patch | 24 + ...Player-spawnParticle-x-y-z-precision-loss.patch | 19 - .../0428-Add-LivingEntity-clearActiveItem.patch | 24 - .../server/0428-Add-PlayerItemCooldownEvent.patch | 81 + .../server/0429-Add-PlayerItemCooldownEvent.patch | 81 - ...ly-improve-performance-of-the-end-generat.patch | 63 + patches/server/0430-More-lightning-API.patch | 37 + ...ly-improve-performance-of-the-end-generat.patch | 63 - ...mbing-should-not-bypass-cramming-gamerule.patch | 156 + patches/server/0431-More-lightning-API.patch | 37 - ...32-Add-missing-default-perms-for-commands.patch | 178 + ...mbing-should-not-bypass-cramming-gamerule.patch | 156 - .../server/0433-Add-PlayerShearBlockEvent.patch | 78 + ...33-Add-missing-default-perms-for-commands.patch | 178 - .../server/0434-Add-PlayerShearBlockEvent.patch | 78 - patches/server/0434-Limit-recipe-packets.patch | 41 + ...35-Fix-CraftSound-backwards-compatibility.patch | 21 + patches/server/0435-Limit-recipe-packets.patch | 41 - ...36-Fix-CraftSound-backwards-compatibility.patch | 21 - .../0436-Player-Chunk-Load-Unload-Events.patch | 34 + .../0437-Optimize-Dynamic-get-Missing-Keys.patch | 34 + .../0437-Player-Chunk-Load-Unload-Events.patch | 34 - .../0438-Expose-LivingEntity-hurt-direction.patch | 58 + .../0438-Optimize-Dynamic-get-Missing-Keys.patch | 34 - ...9-Add-OBSTRUCTED-reason-to-BedEnterResult.patch | 21 + .../0439-Expose-LivingEntity-hurt-direction.patch | 58 - ...0-Add-OBSTRUCTED-reason-to-BedEnterResult.patch | 21 - ...rom-invalid-ingredient-lists-in-VillagerA.patch | 24 + patches/server/0441-Add-TargetHitEvent.patch | 53 + ...rom-invalid-ingredient-lists-in-VillagerA.patch | 24 - patches/server/0442-Add-TargetHitEvent.patch | 53 - .../0442-MC-4-Fix-item-position-desync.patch | 50 + .../0443-Additional-Block-Material-API.patch | 40 + .../0443-MC-4-Fix-item-position-desync.patch | 50 - ...-to-get-Material-from-Boats-and-Minecarts.patch | 62 + .../0444-Additional-Block-Material-API.patch | 40 - ...-to-get-Material-from-Boats-and-Minecarts.patch | 62 - ...ling-mob-spawner-spawn-egg-transformation.patch | 19 + ...ling-mob-spawner-spawn-egg-transformation.patch | 19 - ...0446-Fix-Not-a-string-Map-Conversion-spam.patch | 45 + .../0447-Add-PlayerFlowerPotManipulateEvent.patch | 48 + ...0447-Fix-Not-a-string-Map-Conversion-spam.patch | 45 - .../0448-Add-PlayerFlowerPotManipulateEvent.patch | 48 - ...interact-event-not-being-called-sometimes.patch | 48 + ...interact-event-not-being-called-sometimes.patch | 48 - .../server/0449-Zombie-API-breaking-doors.patch | 24 + .../0450-Fix-nerfed-slime-when-splitting.patch | 18 + .../server/0450-Zombie-API-breaking-doors.patch | 24 - .../server/0451-Add-EntityLoadCrossbowEvent.patch | 68 + .../0451-Fix-nerfed-slime-when-splitting.patch | 18 - .../server/0452-Add-EntityLoadCrossbowEvent.patch | 68 - .../server/0452-Add-WorldGameRuleChangeEvent.patch | 100 + .../0453-Add-ServerResourcesReloadedEvent.patch | 54 + .../server/0453-Add-WorldGameRuleChangeEvent.patch | 100 - .../0454-Add-ServerResourcesReloadedEvent.patch | 54 - ...d-world-settings-for-mobs-picking-up-loot.patch | 32 + .../server/0455-Add-BlockFailedDispenseEvent.patch | 50 + ...d-world-settings-for-mobs-picking-up-loot.patch | 32 - .../server/0456-Add-BlockFailedDispenseEvent.patch | 50 - .../0456-Add-PlayerLecternPageChangeEvent.patch | 46 + .../0457-Add-PlayerLecternPageChangeEvent.patch | 46 - .../0457-Add-PlayerLoomPatternSelectEvent.patch | 45 + .../0458-Add-PlayerLoomPatternSelectEvent.patch | 45 - ...458-Configurable-door-breaking-difficulty.patch | 37 + ...459-Configurable-door-breaking-difficulty.patch | 37 - ...59-Empty-commands-shall-not-be-dispatched.patch | 18 + ...60-Empty-commands-shall-not-be-dispatched.patch | 18 - patches/server/0460-Remove-stale-POIs.patch | 22 + .../server/0461-Fix-villager-boat-exploit.patch | 25 + patches/server/0461-Remove-stale-POIs.patch | 22 - patches/server/0462-Add-sendOpLevel-API.patch | 53 + .../server/0462-Fix-villager-boat-exploit.patch | 25 - ...dd-RegistryAccess-for-managing-Registries.patch | 1405 + patches/server/0463-Add-sendOpLevel-API.patch | 53 - ...dd-RegistryAccess-for-managing-Registries.patch | 1405 - .../server/0464-Add-StructuresLocateEvent.patch | 36 + .../server/0465-Add-StructuresLocateEvent.patch | 36 - ...option-for-requiring-a-player-participant.patch | 42 + ...option-for-requiring-a-player-participant.patch | 42 - ...-component-with-empty-text-instead-of-thr.patch | 25 + .../0467-Make-schedule-command-per-world.patch | 28 + ...-component-with-empty-text-instead-of-thr.patch | 25 - .../0468-Configurable-max-leash-distance.patch | 32 + .../0468-Make-schedule-command-per-world.patch | 28 - .../server/0469-Add-BlockPreDispenseEvent.patch | 46 + .../0469-Configurable-max-leash-distance.patch | 32 - .../server/0470-Add-BlockPreDispenseEvent.patch | 46 - .../0470-Add-PlayerChangeBeaconEffectEvent.patch | 38 + .../0471-Add-PlayerChangeBeaconEffectEvent.patch | 38 - ...-toggle-for-always-placing-the-dragon-egg.patch | 19 + ...72-Add-PlayerStonecutterRecipeSelectEvent.patch | 57 + ...-toggle-for-always-placing-the-dragon-egg.patch | 19 - ...73-Add-PlayerStonecutterRecipeSelectEvent.patch | 57 - .../server/0473-Expand-EntityUnleashEvent.patch | 174 + .../server/0474-Expand-EntityUnleashEvent.patch | 174 - ...Reset-shield-blocking-on-dimension-change.patch | 22 + patches/server/0475-Add-DragonEggFormEvent.patch | 34 + ...Reset-shield-blocking-on-dimension-change.patch | 22 - patches/server/0476-Add-DragonEggFormEvent.patch | 34 - patches/server/0476-Add-EntityMoveEvent.patch | 55 + patches/server/0477-Add-EntityMoveEvent.patch | 55 - ...n-to-disable-pathfinding-updates-on-block.patch | 26 + .../0478-Inline-shift-direction-fields.patch | 56 + ...n-to-disable-pathfinding-updates-on-block.patch | 26 - ...-Allow-adding-items-to-BlockDropItemEvent.patch | 44 + .../0479-Inline-shift-direction-fields.patch | 56 - ...-getMainThreadExecutor-to-BukkitScheduler.patch | 26 + ...-Allow-adding-items-to-BlockDropItemEvent.patch | 44 - ...-getMainThreadExecutor-to-BukkitScheduler.patch | 26 - ...iving-entity-allow-attribute-registration.patch | 57 + ...0482-fix-dead-slime-setSize-invincibility.patch | 19 + ...iving-entity-allow-attribute-registration.patch | 57 - ...etRecipes-should-return-an-immutable-list.patch | 19 + ...0483-fix-dead-slime-setSize-invincibility.patch | 19 - patches/server/0484-Expose-Tracked-Players.patch | 32 + ...etRecipes-should-return-an-immutable-list.patch | 19 - patches/server/0485-Expose-Tracked-Players.patch | 32 - patches/server/0485-Improve-ServerGUI.patch | 431 + patches/server/0486-Improve-ServerGUI.patch | 431 - .../0486-fix-converting-txt-to-json-file.patch | 61 + patches/server/0487-Add-worldborder-events.patch | 72 + .../0487-fix-converting-txt-to-json-file.patch | 61 - .../server/0488-Add-PlayerNameEntityEvent.patch | 26 + patches/server/0488-Add-worldborder-events.patch | 72 - .../server/0489-Add-PlayerNameEntityEvent.patch | 26 - .../server/0489-Add-recipe-to-cook-events.patch | 44 + patches/server/0490-Add-Block-isValidTool.patch | 20 + .../server/0490-Add-recipe-to-cook-events.patch | 44 - patches/server/0491-Add-Block-isValidTool.patch | 20 - ...Allow-using-signs-inside-spawn-protection.patch | 19 + ...Allow-using-signs-inside-spawn-protection.patch | 19 - patches/server/0492-Expand-world-key-API.patch | 84 + ...ast-alternative-constructor-for-Rotations.patch | 29 + patches/server/0493-Expand-world-key-API.patch | 84 - ...ast-alternative-constructor-for-Rotations.patch | 29 - ...carried-item-when-player-has-disconnected.patch | 27 + ...carried-item-when-player-has-disconnected.patch | 27 - ...d-whitelist-use-configurable-kick-message.patch | 19 + ...on-t-ignore-result-of-PlayerEditBookEvent.patch | 19 + ...d-whitelist-use-configurable-kick-message.patch | 19 - ...on-t-ignore-result-of-PlayerEditBookEvent.patch | 19 - patches/server/0497-Expose-protocol-version.patch | 22 + ...sole-tab-completions-for-brigadier-comman.patch | 445 + patches/server/0498-Expose-protocol-version.patch | 22 - ...sole-tab-completions-for-brigadier-comman.patch | 445 - ...layerItemConsumeEvent-cancelling-properly.patch | 22 + patches/server/0500-Add-bypass-host-check.patch | 30 + ...layerItemConsumeEvent-cancelling-properly.patch | 22 - patches/server/0501-Add-bypass-host-check.patch | 30 - .../0501-Set-area-affect-cloud-rotation.patch | 19 + .../0502-Set-area-affect-cloud-rotation.patch | 19 - .../0502-add-isDeeplySleeping-to-HumanEntity.patch | 24 + .../0503-add-consumeFuel-to-FurnaceBurnEvent.patch | 19 + .../0503-add-isDeeplySleeping-to-HumanEntity.patch | 24 - .../0504-add-consumeFuel-to-FurnaceBurnEvent.patch | 19 - ...dd-get-set-drop-chance-to-EntityEquipment.patch | 72 + ...dd-get-set-drop-chance-to-EntityEquipment.patch | 72 - ...0505-fix-PigZombieAngerEvent-cancellation.patch | 35 + ...0506-fix-PigZombieAngerEvent-cancellation.patch | 35 - ...0506-fix-PlayerItemHeldEvent-firing-twice.patch | 18 + patches/server/0507-Add-PlayerDeepSleepEvent.patch | 24 + ...0507-fix-PlayerItemHeldEvent-firing-twice.patch | 18 - patches/server/0508-Add-PlayerDeepSleepEvent.patch | 24 - patches/server/0508-More-World-API.patch | 57 + .../server/0509-Add-PlayerBedFailEnterEvent.patch | 36 + patches/server/0509-More-World-API.patch | 57 - .../server/0510-Add-PlayerBedFailEnterEvent.patch | 36 - ...ethods-to-convert-between-Component-and-B.patch | 55 + ...erRespawnEvent-fix-passed-parameter-issue.patch | 26 + ...ethods-to-convert-between-Component-and-B.patch | 55 - ...erRespawnEvent-fix-passed-parameter-issue.patch | 26 - ...uce-beacon-activation-deactivation-events.patch | 37 + ...0513-Add-Channel-initialization-listeners.patch | 155 + ...uce-beacon-activation-deactivation-events.patch | 37 - ...0514-Add-Channel-initialization-listeners.patch | 155 - ...ty-commands-if-tab-completion-is-disabled.patch | 24 + .../server/0515-Add-more-WanderingTrader-API.patch | 65 + ...ty-commands-if-tab-completion-is-disabled.patch | 24 - ...0516-Add-EntityBlockStorage-clearEntities.patch | 38 + .../server/0516-Add-more-WanderingTrader-API.patch | 65 - ...ure-message-to-PlayerAdvancementDoneEvent.patch | 35 + ...0517-Add-EntityBlockStorage-clearEntities.patch | 38 - ...ure-message-to-PlayerAdvancementDoneEvent.patch | 35 - .../server/0518-Add-HiddenPotionEffect-API.patch | 29 + .../server/0519-Add-HiddenPotionEffect-API.patch | 29 - patches/server/0519-Inventory-close.patch | 25 + ...d-burn-in-sunlight-API-for-Phantoms-and-S.patch | 130 + patches/server/0520-Inventory-close.patch | 25 - ...d-burn-in-sunlight-API-for-Phantoms-and-S.patch | 130 - patches/server/0521-Add-basic-Datapack-API.patch | 209 + patches/server/0522-Add-basic-Datapack-API.patch | 209 - ...nvironment-variable-to-disable-server-gui.patch | 18 + ...nvironment-variable-to-disable-server-gui.patch | 18 - .../0523-Expand-PlayerGameModeChangeEvent.patch | 161 + .../0524-Expand-PlayerGameModeChangeEvent.patch | 161 - .../server/0524-ItemStack-repair-check-API.patch | 72 + .../server/0525-ItemStack-repair-check-API.patch | 72 - patches/server/0525-More-Enchantment-API.patch | 105 + patches/server/0526-More-Enchantment-API.patch | 105 - ...526-Move-range-check-for-block-placing-up.patch | 22 + patches/server/0527-Add-Mob-lookAt-API.patch | 64 + ...527-Move-range-check-for-block-placing-up.patch | 22 - patches/server/0528-Add-Mob-lookAt-API.patch | 64 - ...heck-if-bucket-dispenses-will-succeed-for.patch | 28 + .../0529-Add-Unix-domain-socket-support.patch | 137 + ...heck-if-bucket-dispenses-will-succeed-for.patch | 28 - .../server/0530-Add-EntityInsideBlockEvent.patch | 306 + .../0530-Add-Unix-domain-socket-support.patch | 137 - .../server/0531-Add-EntityInsideBlockEvent.patch | 306 - .../0531-Improve-item-default-attribute-API.patch | 80 + ...-Add-cause-to-Weather-ThunderChangeEvents.patch | 118 + .../0532-Improve-item-default-attribute-API.patch | 80 - ...-Add-cause-to-Weather-ThunderChangeEvents.patch | 118 - patches/server/0533-More-Lidded-Block-API.patch | 79 + .../0534-Limit-item-frame-cursors-on-maps.patch | 30 + patches/server/0534-More-Lidded-Block-API.patch | 79 - .../server/0535-Add-PlayerKickEvent-causes.patch | 548 + .../0535-Limit-item-frame-cursors-on-maps.patch | 30 - .../server/0536-Add-PlayerKickEvent-causes.patch | 548 - .../0536-Add-PufferFishStateChangeEvent.patch | 50 + .../0537-Add-PufferFishStateChangeEvent.patch | 50 - ...x-PlayerBucketEmptyEvent-result-itemstack.patch | 42 + ...x-PlayerBucketEmptyEvent-result-itemstack.patch | 42 - ...-PalettedContainer-instead-of-ThreadingDe.patch | 91 + ...option-to-fix-items-merging-through-walls.patch | 25 + ...-PalettedContainer-instead-of-ThreadingDe.patch | 91 - .../server/0540-Add-BellRevealRaiderEvent.patch | 33 + ...option-to-fix-items-merging-through-walls.patch | 25 - .../server/0541-Add-BellRevealRaiderEvent.patch | 33 - .../0541-Fix-invulnerable-end-crystals.patch | 65 + .../0542-Add-ElderGuardianAppearanceEvent.patch | 48 + .../0542-Fix-invulnerable-end-crystals.patch | 65 - .../0543-Add-ElderGuardianAppearanceEvent.patch | 48 - ...timize-Biome-Mob-Lookups-for-Mob-Spawning.patch | 53 + patches/server/0544-Line-Of-Sight-Changes.patch | 74 + ...timize-Biome-Mob-Lookups-for-Mob-Spawning.patch | 53 - patches/server/0545-Line-Of-Sight-Changes.patch | 74 - .../server/0545-add-per-world-spawn-limits.patch | 24 + .../server/0546-Fix-potions-splash-events.patch | 181 + .../server/0546-add-per-world-spawn-limits.patch | 24 - .../server/0547-Add-more-LimitedRegion-API.patch | 56 + .../server/0547-Fix-potions-splash-events.patch | 181 - .../server/0548-Add-more-LimitedRegion-API.patch | 56 - ...-Fix-PlayerDropItemEvent-using-wrong-item.patch | 57 + ...-Fix-PlayerDropItemEvent-using-wrong-item.patch | 57 - patches/server/0549-Missing-Entity-API.patch | 1402 + ...value-of-Block-applyBoneMeal-always-being.patch | 19 + patches/server/0550-Missing-Entity-API.patch | 1402 - ...value-of-Block-applyBoneMeal-always-being.patch | 19 - ...Use-getChunkIfLoadedImmediately-in-places.patch | 53 + ...ands-from-signs-not-firing-command-events.patch | 121 + ...Use-getChunkIfLoadedImmediately-in-places.patch | 53 - patches/server/0553-Add-PlayerArmSwingEvent.patch | 19 + ...ands-from-signs-not-firing-command-events.patch | 121 - patches/server/0554-Add-PlayerArmSwingEvent.patch | 19 - ...x-kick-event-leave-message-not-being-sent.patch | 127 + ...55-Don-t-apply-cramming-damage-to-players.patch | 25 + ...x-kick-event-leave-message-not-being-sent.patch | 127 - ...56-Don-t-apply-cramming-damage-to-players.patch | 25 - ...ons-and-timings-for-sensors-and-behaviors.patch | 88 + .../0557-Add-missing-forceDrop-toggles.patch | 124 + ...ons-and-timings-for-sensors-and-behaviors.patch | 88 - .../0558-Add-missing-forceDrop-toggles.patch | 124 - patches/server/0558-Stinger-API.patch | 50 + .../server/0559-Add-System.out-err-catcher.patch | 118 + patches/server/0559-Stinger-API.patch | 50 - .../server/0560-Add-System.out-err-catcher.patch | 118 - ...event-AFK-kick-while-watching-end-credits.patch | 19 + ...ing-writing-of-comments-to-server.propert.patch | 69 + ...event-AFK-kick-while-watching-end-credits.patch | 19 - patches/server/0562-Add-PlayerSetSpawnEvent.patch | 204 + ...ing-writing-of-comments-to-server.propert.patch | 69 - patches/server/0563-Add-PlayerSetSpawnEvent.patch | 204 - ...-hoppers-respect-inventory-max-stack-size.patch | 30 + ...-hoppers-respect-inventory-max-stack-size.patch | 30 - ...-Optimize-entity-tracker-passenger-checks.patch | 19 + ...Config-option-for-Piglins-guarding-chests.patch | 18 + ...-Optimize-entity-tracker-passenger-checks.patch | 19 - .../server/0566-Add-EntityDamageItemEvent.patch | 94 + ...Config-option-for-Piglins-guarding-chests.patch | 18 - .../server/0567-Add-EntityDamageItemEvent.patch | 94 - ...567-Optimize-indirect-passenger-iteration.patch | 53 + ...ble-item-frame-map-cursor-update-interval.patch | 19 + ...568-Optimize-indirect-passenger-iteration.patch | 53 - ...rEye-target-without-changing-other-things.patch | 54 + ...ble-item-frame-map-cursor-update-interval.patch | 19 - patches/server/0570-Add-BlockBreakBlockEvent.patch | 87 + ...rEye-target-without-changing-other-things.patch | 54 - patches/server/0571-Add-BlockBreakBlockEvent.patch | 87 - ...revent-data-components-copy-in-smithing-r.patch | 157 + patches/server/0572-More-CommandBlock-API.patch | 101 + ...revent-data-components-copy-in-smithing-r.patch | 157 - ...73-Add-missing-team-sidebar-display-slots.patch | 114 + patches/server/0573-More-CommandBlock-API.patch | 101 - .../0574-Add-back-EntityPortalExitEvent.patch | 48 + ...74-Add-missing-team-sidebar-display-slots.patch | 114 - .../0575-Add-back-EntityPortalExitEvent.patch | 48 - ...ods-to-find-targets-for-lightning-strikes.patch | 60 + ...ods-to-find-targets-for-lightning-strikes.patch | 60 - .../0576-Get-entity-default-attributes.patch | 151 + .../0577-Get-entity-default-attributes.patch | 151 - patches/server/0577-Left-handed-API.patch | 27 + patches/server/0578-Add-more-advancement-API.patch | 213 + patches/server/0578-Left-handed-API.patch | 27 - .../0579-Add-ItemFactory-getSpawnEgg-API.patch | 58 + patches/server/0579-Add-more-advancement-API.patch | 213 - .../0580-Add-ItemFactory-getSpawnEgg-API.patch | 58 - patches/server/0580-Add-critical-damage-API.patch | 101 + patches/server/0581-Add-critical-damage-API.patch | 101 - .../0581-Fix-issues-with-mob-conversion.patch | 74 + ...dd-hasCollision-methods-to-various-places.patch | 56 + .../0582-Fix-issues-with-mob-conversion.patch | 74 - ...dd-hasCollision-methods-to-various-places.patch | 56 - patches/server/0583-Goat-ram-API.patch | 42 + ...0584-Add-API-for-resetting-a-single-score.patch | 24 + patches/server/0584-Goat-ram-API.patch | 42 - ...0585-Add-API-for-resetting-a-single-score.patch | 24 - .../0585-Add-Raw-Byte-Entity-Serialization.patch | 90 + .../0586-Add-Raw-Byte-Entity-Serialization.patch | 90 - .../0586-Vanilla-command-permission-fixes.patch | 79 + ...close-logic-for-inventories-on-chunk-unlo.patch | 68 + .../0587-Vanilla-command-permission-fixes.patch | 79 - ...close-logic-for-inventories-on-chunk-unlo.patch | 68 - .../0588-Fix-GameProfileCache-concurrency.patch | 126 + .../0589-Fix-GameProfileCache-concurrency.patch | 126 - .../0589-Improve-and-expand-AsyncCatcher.patch | 227 + ...Add-paper-mobcaps-and-paper-playermobcaps.patch | 343 + .../0590-Improve-and-expand-AsyncCatcher.patch | 227 - ...Add-paper-mobcaps-and-paper-playermobcaps.patch | 343 - ...1-Sanitize-ResourceLocation-error-logging.patch | 28 + ...-Manually-inline-methods-in-BlockPosition.patch | 63 + ...2-Sanitize-ResourceLocation-error-logging.patch | 28 - ...-Manually-inline-methods-in-BlockPosition.patch | 63 - ...scheduler-threads-according-to-the-plugin.patch | 33 + ...nlined-getChunkAt-has-inlined-logic-for-l.patch | 31 + ...scheduler-threads-according-to-the-plugin.patch | 33 - ...neighbour-chunk-data-off-disk-when-conver.patch | 21 + ...nlined-getChunkAt-has-inlined-logic-for-l.patch | 31 - ...p-fluid-state-when-raytracing-skip-air-bl.patch | 26 + ...neighbour-chunk-data-off-disk-when-conver.patch | 21 - ...p-fluid-state-when-raytracing-skip-air-bl.patch | 26 - ...597-Oprimise-map-impl-for-tracked-players.patch | 21 + .../server/0598-Add-missing-InventoryType.patch | 22 + ...598-Oprimise-map-impl-for-tracked-players.patch | 21 - .../server/0599-Add-missing-InventoryType.patch | 22 - ...99-Optimise-BlockSoil-nearby-water-lookup.patch | 52 + ...t-inventory-not-closing-on-entity-removal.patch | 22 + ...00-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/0603-Add-packet-limiter-config.patch | 108 + ...nd-to-ServerboundCommandSuggestionPacket-.patch | 23 - .../server/0604-Add-packet-limiter-config.patch | 108 - ...PatternColor-on-tropical-fish-bucket-meta.patch | 72 + .../server/0605-Ensure-valid-vehicle-status.patch | 19 + ...PatternColor-on-tropical-fish-bucket-meta.patch | 72 - .../server/0606-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 - ...08-Don-t-log-debug-logging-being-disabled.patch | 19 + ...corator-causing-a-crash-when-trying-to-ge.patch | 19 - ...09-Don-t-log-debug-logging-being-disabled.patch | 19 - ...x-various-menus-with-empty-level-accesses.patch | 23 + .../server/0610-Preserve-overstacked-loot.patch | 27 + ...x-various-menus-with-empty-level-accesses.patch | 23 - .../server/0611-Preserve-overstacked-loot.patch | 27 - ...11-Update-head-rotation-in-missing-places.patch | 29 + ...12-Update-head-rotation-in-missing-places.patch | 29 - ...event-unintended-light-block-manipulation.patch | 25 + .../0613-Fix-CraftCriteria-defaults-map.patch | 19 + ...event-unintended-light-block-manipulation.patch | 25 - .../0614-Fix-CraftCriteria-defaults-map.patch | 19 - .../0614-Fix-upstreams-block-state-factories.patch | 491 + .../server/0615-Configurable-feature-seeds.patch | 27 + .../0615-Fix-upstreams-block-state-factories.patch | 491 - .../0616-Add-root-admin-user-detection.patch | 62 + .../server/0616-Configurable-feature-seeds.patch | 27 - .../0617-Add-root-admin-user-detection.patch | 62 - ...7-don-t-attempt-to-teleport-dead-entities.patch | 19 + ...excessive-velocity-through-repeated-crits.patch | 41 + ...8-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/0620-Fix-Spigot-growth-modifiers.patch | 141 + ...nt-side-code-using-deprecated-for-removal.patch | 30 - .../server/0621-Fix-Spigot-growth-modifiers.patch | 141 - ...tainerOpenersCounter-openCount-from-going.patch | 18 + .../0622-Add-PlayerItemFrameChangeEvent.patch | 61 + ...tainerOpenersCounter-openCount-from-going.patch | 18 - .../0623-Add-PlayerItemFrameChangeEvent.patch | 61 - patches/server/0623-Optimize-HashMapPalette.patch | 57 + ...apshot-isSectionEmpty-int-and-optimize-Pa.patch | 44 + patches/server/0624-Optimize-HashMapPalette.patch | 57 - patches/server/0625-Add-more-Campfire-API.patch | 111 + ...apshot-isSectionEmpty-int-and-optimize-Pa.patch | 44 - patches/server/0626-Add-more-Campfire-API.patch | 111 - ...6-Forward-CraftEntity-in-teleport-command.patch | 35 + ...7-Forward-CraftEntity-in-teleport-command.patch | 35 - .../server/0627-Improve-scoreboard-entries.patch | 88 + patches/server/0628-Entity-powdered-snow-API.patch | 42 + .../server/0628-Improve-scoreboard-entries.patch | 88 - .../0629-Add-API-for-item-entity-health.patch | 34 + patches/server/0629-Entity-powdered-snow-API.patch | 42 - .../0630-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/0633-Bucketable-API.patch | 69 + ...el-and-canSmelt-methods-to-FurnaceInvento.patch | 32 - patches/server/0634-Bucketable-API.patch | 69 - patches/server/0634-Validate-usernames.patch | 76 + ...ke-water-animal-spawn-height-configurable.patch | 21 + patches/server/0635-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 - .../0639-Multiple-Entries-with-Scoreboards.patch | 125 + .../0640-Multiple-Entries-with-Scoreboards.patch | 125 - .../0640-Reset-placed-block-on-exception.patch | 39 + ...1-Add-configurable-height-for-slime-spawn.patch | 35 + .../0641-Reset-placed-block-on-exception.patch | 39 - ...2-Add-configurable-height-for-slime-spawn.patch | 35 - .../0642-Fix-xp-reward-for-baby-zombies.patch | 32 + .../0643-Fix-xp-reward-for-baby-zombies.patch | 32 - ...643-Multi-Block-Change-API-Implementation.patch | 62 + patches/server/0644-Fix-NotePlayEvent.patch | 54 + ...644-Multi-Block-Change-API-Implementation.patch | 62 - patches/server/0645-Fix-NotePlayEvent.patch | 54 - patches/server/0645-Freeze-Tick-Lock-API.patch | 82 + patches/server/0646-Freeze-Tick-Lock-API.patch | 82 - .../server/0646-More-PotionEffectType-API.patch | 98 + .../server/0647-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 - ...49-Add-missing-structure-set-seed-configs.patch | 399 + ...50-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/0652-Add-GameEvent-tags.patch | 81 + ...-Validate-calls-to-CraftServer-getSpawnLi.patch | 20 - patches/server/0653-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/0654-Furnace-RecipesUsed-API.patch | 48 + ...-Configurable-sculk-sensor-listener-range.patch | 106 + patches/server/0655-Furnace-RecipesUsed-API.patch | 48 - .../server/0656-Add-missing-block-data-API.patch | 214 + ...-Configurable-sculk-sensor-listener-range.patch | 106 - .../server/0657-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/0659-Custom-Potion-Mixes.patch | 329 + ...d-into-worldlist-before-initing-the-world.patch | 41 - patches/server/0660-Custom-Potion-Mixes.patch | 329 - .../0660-Force-close-world-loading-screen.patch | 32 + .../0661-Fix-falling-block-spawn-methods.patch | 57 + .../0661-Force-close-world-loading-screen.patch | 32 - .../0662-Expose-furnace-minecart-push-values.patch | 42 + .../0662-Fix-falling-block-spawn-methods.patch | 57 - .../0663-Expose-furnace-minecart-push-values.patch | 42 - ...ing-ProjectileHitEvent-for-piercing-arrow.patch | 40 + ...ing-ProjectileHitEvent-for-piercing-arrow.patch | 40 - patches/server/0664-More-Projectile-API.patch | 932 + ...665-Fix-swamp-hut-cat-generation-deadlock.patch | 64 + patches/server/0665-More-Projectile-API.patch | 932 - ...-vehicle-movement-from-players-while-tele.patch | 24 + ...666-Fix-swamp-hut-cat-generation-deadlock.patch | 64 - ...-vehicle-movement-from-players-while-tele.patch | 24 - .../0667-Implement-getComputedBiome-API.patch | 61 + .../0668-Implement-getComputedBiome-API.patch | 61 - .../server/0668-Make-some-itemstacks-nonnull.patch | 28 + .../0669-Implement-enchantWithLevels-API.patch | 58 + .../server/0669-Make-some-itemstacks-nonnull.patch | 28 - .../server/0670-Fix-saving-in-unloadWorld.patch | 20 + .../0670-Implement-enchantWithLevels-API.patch | 58 - .../server/0671-Buffer-OOB-setBlock-calls.patch | 42 + .../server/0671-Fix-saving-in-unloadWorld.patch | 20 - .../0672-Add-TameableDeathMessageEvent.patch | 24 + .../server/0672-Buffer-OOB-setBlock-calls.patch | 42 - .../0673-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 | 38 + ...ity-passenger-world-matches-ridden-entity.patch | 20 - ...677-Allow-changing-the-EnderDragon-podium.patch | 142 + ...rce-keys-and-optimize-reference-Holder-ta.patch | 38 - ...678-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 - ...e-instead-of-display-name-in-PlayerList-g.patch | 20 + .../server/0680-Expand-PlayerItemDamageEvent.patch | 23 + ...e-instead-of-display-name-in-PlayerList-g.patch | 20 - .../server/0681-Expand-PlayerItemDamageEvent.patch | 23 - .../server/0681-WorldCreator-keepSpawnLoaded.patch | 19 + ...ix-CME-in-CraftPersistentDataTypeRegistry.patch | 19 + .../server/0682-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/0687-Add-PlayerStopUsingItemEvent.patch | 18 + ...owder-snow-cauldrons-not-turning-to-water.patch | 45 - .../server/0688-Add-PlayerStopUsingItemEvent.patch | 18 - patches/server/0688-Don-t-tick-markers.patch | 36 + patches/server/0689-Don-t-tick-markers.patch | 36 - patches/server/0689-Expand-FallingBlock-API.patch | 107 + .../0690-Add-support-for-Proxy-Protocol.patch | 65 + patches/server/0690-Expand-FallingBlock-API.patch | 107 - .../0691-Add-support-for-Proxy-Protocol.patch | 65 - ...691-Fix-OfflinePlayer-getBedSpawnLocation.patch | 46 + ...eInventory-for-smokers-and-blast-furnaces.patch | 49 + ...692-Fix-OfflinePlayer-getBedSpawnLocation.patch | 46 - ...eInventory-for-smokers-and-blast-furnaces.patch | 49 - .../0693-Sanitize-sent-BlockEntity-NBT.patch | 50 + ...ponent-selector-resolving-in-books-by-def.patch | 19 + .../0694-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 + .../0697-Dont-resent-entity-on-art-update.patch | 19 + ...eption-on-world-create-while-being-ticked.patch | 78 - .../server/0698-Add-WardenAngerChangeEvent.patch | 39 + .../0698-Dont-resent-entity-on-art-update.patch | 19 - .../server/0699-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/0701-Nameable-Banner-API.patch | 50 + ...on-t-broadcast-messages-to-command-blocks.patch | 34 + patches/server/0702-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/0705-Add-Player-getFishHook.patch | 26 + ...-SplashPotion-and-LingeringPotion-spawnin.patch | 21 - patches/server/0706-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/0708-Fix-Bee-flower-NPE.patch | 19 + patches/server/0709-Fix-Bee-flower-NPE.patch | 19 - patches/server/0709-More-Teleport-API.patch | 265 + .../server/0710-Add-EntityPortalReadyEvent.patch | 25 + patches/server/0710-More-Teleport-API.patch | 265 - .../server/0711-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 | 105 + ...14-Custom-Chat-Completion-Suggestions-API.patch | 35 + ...-Warn-on-plugins-accessing-faraway-chunks.patch | 105 - .../0715-Add-and-fix-missing-BlockFadeEvents.patch | 71 + ...15-Custom-Chat-Completion-Suggestions-API.patch | 35 - .../0716-Add-and-fix-missing-BlockFadeEvents.patch | 71 - patches/server/0716-Collision-API.patch | 48 + patches/server/0717-Collision-API.patch | 48 - ...-command-message-for-brigadier-syntax-exc.patch | 20 + patches/server/0718-Block-Ticking-API.patch | 63 + ...-command-message-for-brigadier-syntax-exc.patch | 20 - .../0719-Add-Velocity-IP-Forwarding-Support.patch | 242 + patches/server/0719-Block-Ticking-API.patch | 63 - .../0720-Add-NamespacedKey-biome-methods.patch | 28 + .../0720-Add-Velocity-IP-Forwarding-Support.patch | 242 - .../0721-Add-NamespacedKey-biome-methods.patch | 28 - ...721-Fix-plugin-loggers-on-server-shutdown.patch | 67 + ...722-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/0724-Missing-eating-regain-reason.patch | 45 + .../server/0725-Missing-eating-regain-reason.patch | 45 - patches/server/0725-Missing-effect-cause.patch | 32 + ...array-serialization-deserialization-for-P.patch | 39 + patches/server/0726-Missing-effect-cause.patch | 32 - ...727-Add-source-block-to-BlockPhysicsEvent.patch | 42 + ...array-serialization-deserialization-for-P.patch | 39 - ...728-Add-source-block-to-BlockPhysicsEvent.patch | 42 - .../0728-Configurable-chat-thread-limit.patch | 47 + .../0729-Configurable-chat-thread-limit.patch | 47 - ...fects-of-WorldCreator-keepSpawnLoaded-ret.patch | 25 + ...fects-of-WorldCreator-keepSpawnLoaded-ret.patch | 25 - .../0730-fix-Jigsaw-block-kicking-user.patch | 24 + .../0731-fix-Jigsaw-block-kicking-user.patch | 24 - ...ockFormEvent-for-mud-converting-into-clay.patch | 25 + .../server/0732-Add-getDrops-to-BlockState.patch | 37 + ...ockFormEvent-for-mud-converting-into-clay.patch | 25 - .../server/0733-Add-getDrops-to-BlockState.patch | 37 - .../server/0733-Fix-a-bunch-of-vanilla-bugs.patch | 385 + .../server/0734-Fix-a-bunch-of-vanilla-bugs.patch | 385 - ...cessary-onTrackingStart-during-navigation.patch | 28 + .../0735-Fix-custom-piglin-loved-items.patch | 21 + ...cessary-onTrackingStart-during-navigation.patch | 28 - .../server/0736-EntityPickupItemEvent-fixes.patch | 73 + .../0736-Fix-custom-piglin-loved-items.patch | 21 - ...andle-interactions-with-items-on-cooldown.patch | 60 + .../server/0737-EntityPickupItemEvent-fixes.patch | 73 - .../0738-Add-PlayerInventorySlotChangeEvent.patch | 65 + ...andle-interactions-with-items-on-cooldown.patch | 60 - .../0739-Add-PlayerInventorySlotChangeEvent.patch | 65 - .../0739-Elder-Guardian-appearance-API.patch | 24 + patches/server/0740-Add-entity-knockback-API.patch | 23 + .../0740-Elder-Guardian-appearance-API.patch | 24 - patches/server/0741-Add-entity-knockback-API.patch | 23 - patches/server/0741-Detect-headless-JREs.patch | 51 + patches/server/0742-Detect-headless-JREs.patch | 51 - ...entity-vehicle-collision-event-not-called.patch | 27 + patches/server/0743-Add-EntityToggleSitEvent.patch | 100 + ...entity-vehicle-collision-event-not-called.patch | 27 - patches/server/0744-Add-EntityToggleSitEvent.patch | 100 - .../server/0744-Add-fire-tick-delay-option.patch | 34 + patches/server/0745-Add-Moving-Piston-API.patch | 46 + .../server/0745-Add-fire-tick-delay-option.patch | 34 - patches/server/0746-Add-Moving-Piston-API.patch | 46 - .../server/0746-Ignore-impossible-spawn-tick.patch | 18 + ...rgument-and-EntitySelectorParser-permissi.patch | 41 + .../server/0747-Ignore-impossible-spawn-tick.patch | 18 - ...rgument-and-EntitySelectorParser-permissi.patch | 41 - ...ombustEvent-cancellation-cant-fully-preve.patch | 37 + .../0749-Add-PrePlayerAttackEntityEvent.patch | 30 + ...ombustEvent-cancellation-cant-fully-preve.patch | 37 - .../0750-Add-PrePlayerAttackEntityEvent.patch | 30 - ...-ensure-reset-EnderDragon-boss-event-name.patch | 39 + .../0751-Add-Player-Warden-Warning-API.patch | 57 + ...-ensure-reset-EnderDragon-boss-event-name.patch | 39 - .../0752-Add-Player-Warden-Warning-API.patch | 57 - ...vanilla-friendly-methods-to-update-trades.patch | 75 + .../0753-Add-paper-dumplisteners-command.patch | 197 + ...vanilla-friendly-methods-to-update-trades.patch | 75 - .../0754-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/0756-ItemStack-damage-API.patch | 121 + patches/server/0757-Friction-API.patch | 245 + patches/server/0757-ItemStack-damage-API.patch | 121 - ...to-control-player-s-insomnia-and-phantoms.patch | 67 + patches/server/0758-Friction-API.patch | 245 - ...to-control-player-s-insomnia-and-phantoms.patch | 67 - ...59-Fix-premature-player-kicks-on-shutdown.patch | 61 + ...60-Fix-premature-player-kicks-on-shutdown.patch | 61 - .../server/0760-Sync-offhand-slot-in-menus.patch | 51 + .../0761-Player-Entity-Tracking-Events.patch | 42 + .../server/0761-Sync-offhand-slot-in-menus.patch | 51 - patches/server/0762-Limit-pet-look-distance.patch | 19 + .../0762-Player-Entity-Tracking-Events.patch | 42 - patches/server/0763-Limit-pet-look-distance.patch | 19 - patches/server/0763-fix-Instruments.patch | 83 + ...ining-for-some-hot-BlockBehavior-and-Flui.patch | 78 + patches/server/0764-fix-Instruments.patch | 83 - patches/server/0765-Add-BlockLockCheckEvent.patch | 70 + ...ining-for-some-hot-BlockBehavior-and-Flui.patch | 78 - patches/server/0766-Add-BlockLockCheckEvent.patch | 70 - .../0766-Add-Sneaking-API-for-Entities.patch | 29 + .../0767-Add-Sneaking-API-for-Entities.patch | 29 - .../server/0767-Improve-logging-and-errors.patch | 104 + patches/server/0768-Improve-PortalEvents.patch | 103 + .../server/0768-Improve-logging-and-errors.patch | 104 - ...ig-option-for-spider-worldborder-climbing.patch | 19 + patches/server/0769-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/0772-Flying-Fall-Damage.patch | 51 + ...collision-moving-velocity-to-VehicleBlock.patch | 28 + patches/server/0773-Flying-Fall-Damage.patch | 51 - ...collision-moving-velocity-to-VehicleBlock.patch | 28 - ...0774-config-for-disabling-entity-tag-tags.patch | 26 + ...-single-player-info-update-packet-on-join.patch | 51 + ...0775-config-for-disabling-entity-tag-tags.patch | 26 - ...-shrink-items-during-EntityResurrectEvent.patch | 36 + ...-single-player-info-update-packet-on-join.patch | 51 - ...-shrink-items-during-EntityResurrectEvent.patch | 36 - patches/server/0777-Win-Screen-API.patch | 38 + ...-CraftItemStack-setAmount-null-assignment.patch | 30 + patches/server/0778-Win-Screen-API.patch | 38 - ...0779-Fix-force-opening-enchantment-tables.patch | 30 + ...-CraftItemStack-setAmount-null-assignment.patch | 30 - patches/server/0780-Add-Entity-Body-Yaw-API.patch | 65 + ...0780-Fix-force-opening-enchantment-tables.patch | 30 - patches/server/0781-Add-Entity-Body-Yaw-API.patch | 65 - ...64-Prevent-sleeping-villagers-moving-towa.patch | 24 + .../server/0782-Add-EntityFertilizeEggEvent.patch | 103 + ...64-Prevent-sleeping-villagers-moving-towa.patch | 24 - .../server/0783-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 - .../0787-Fix-text-display-error-on-spawn.patch | 19 + ...-Fix-inventories-returning-null-Locations.patch | 61 + .../0788-Fix-text-display-error-on-spawn.patch | 19 - patches/server/0789-Add-Shearable-API.patch | 135 + ...-Fix-inventories-returning-null-Locations.patch | 61 - patches/server/0790-Add-Shearable-API.patch | 135 - .../0790-Fix-SpawnEggMeta-get-setSpawnedType.patch | 41 + .../0791-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 - .../0795-Use-array-for-gamerule-storage.patch | 52 + .../0796-Fix-a-couple-of-upstream-bed-issues.patch | 33 + .../0796-Use-array-for-gamerule-storage.patch | 52 - .../0797-Fix-a-couple-of-upstream-bed-issues.patch | 33 - ...0797-Fix-demo-flag-not-enabling-demo-mode.patch | 22 + .../0798-Add-Mob-Experience-reward-API.patch | 22 + ...0798-Fix-demo-flag-not-enabling-demo-mode.patch | 22 - .../0799-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 - .../0801-More-accurate-isInOpenWater-impl.patch | 27 + .../server/0802-Expand-PlayerItemMendEvent.patch | 67 + .../0802-More-accurate-isInOpenWater-impl.patch | 27 - .../server/0803-Expand-PlayerItemMendEvent.patch | 67 - ...-Refresh-ProjectileSource-for-projectiles.patch | 81 + .../server/0804-Add-transient-modifier-API.patch | 41 + ...-Refresh-ProjectileSource-for-projectiles.patch | 81 - .../server/0805-Add-transient-modifier-API.patch | 41 - patches/server/0805-Fix-block-place-logic.patch | 49 + patches/server/0806-Fix-block-place-logic.patch | 49 - ...ot-sound-playing-for-BlockItem-ItemStacks.patch | 23 + ...07-Call-BlockGrowEvent-for-missing-blocks.patch | 39 + ...ot-sound-playing-for-BlockItem-ItemStacks.patch | 23 - ...08-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 + .../0810-Fix-sniffer-removeExploredLocation.patch | 29 + ...fix-MapLike-spam-for-missing-key-selector.patch | 19 - ...ethod-to-remove-all-active-potion-effects.patch | 24 + .../0811-Fix-sniffer-removeExploredLocation.patch | 29 - .../0812-Add-event-for-player-editing-sign.patch | 93 + ...ethod-to-remove-all-active-potion-effects.patch | 24 - .../0813-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 - .../0815-Add-option-to-disable-block-updates.patch | 179 + ...-cmd-permission-levels-for-command-blocks.patch | 90 - .../0816-Add-option-to-disable-block-updates.patch | 179 - .../0816-Call-missing-BlockDispenseEvent.patch | 88 + .../0817-Call-missing-BlockDispenseEvent.patch | 88 - ...t-load-chunks-for-supporting-block-checks.patch | 19 + ...t-load-chunks-for-supporting-block-checks.patch | 19 - .../0818-Optimize-player-lookups-for-beacons.patch | 36 + patches/server/0819-More-Sign-Block-API.patch | 62 + .../0819-Optimize-player-lookups-for-beacons.patch | 36 - patches/server/0820-More-Sign-Block-API.patch | 62 - .../0820-fix-item-meta-for-tadpole-buckets.patch | 63 + patches/server/0821-Fix-BanList-API.patch | 351 + .../0821-fix-item-meta-for-tadpole-buckets.patch | 63 - ...ava-and-water-fluid-explosion-resistance-.patch | 36 + patches/server/0822-Fix-BanList-API.patch | 351 - ...ava-and-water-fluid-explosion-resistance-.patch | 36 - ...823-Fix-possible-NPE-on-painting-creation.patch | 34 + ...824-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/0827-Add-whitelist-events.patch | 34 + ...methyst-throw-both-Spread-and-Grow-Events.patch | 24 - patches/server/0828-Add-whitelist-events.patch | 34 - .../0828-Implement-PlayerFailMoveEvent.patch | 111 + ...0829-Folia-scheduler-and-owned-region-API.patch | 1376 + .../0829-Implement-PlayerFailMoveEvent.patch | 111 - ...0830-Folia-scheduler-and-owned-region-API.patch | 1376 - ...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 - .../0832-Only-capture-actual-tree-growth.patch | 75 + .../0833-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 - .../0835-Use-correct-seed-on-api-world-load.patch | 19 + ...radeData-neighbour-ticks-outside-of-range.patch | 50 + .../0836-Use-correct-seed-on-api-world-load.patch | 19 - .../server/0837-Cache-map-ids-on-item-frames.patch | 39 + ...radeData-neighbour-ticks-outside-of-range.patch | 50 - .../0838-API-for-updating-recipes-on-clients.patch | 113 + .../server/0838-Cache-map-ids-on-item-frames.patch | 39 - .../0839-API-for-updating-recipes-on-clients.patch | 113 - ...39-Fix-custom-statistic-criteria-creation.patch | 23 + patches/server/0840-Bandaid-fix-for-Effect.patch | 179 + ...40-Fix-custom-statistic-criteria-creation.patch | 23 - patches/server/0841-Bandaid-fix-for-Effect.patch | 179 - patches/server/0841-SculkCatalyst-bloom-API.patch | 33 + .../0842-API-for-an-entity-s-scoreboard-name.patch | 24 + patches/server/0842-SculkCatalyst-bloom-API.patch | 33 - .../0843-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/0848-Add-Listing-API-for-Player.patch | 186 + ...ble-entity-tracking-range-by-Y-coordinate.patch | 30 - .../server/0849-Add-Listing-API-for-Player.patch | 186 - ...49-Configurable-Region-Compression-Format.patch | 39 + .../0850-Add-BlockFace-to-BlockDamageEvent.patch | 39 + ...50-Configurable-Region-Compression-Format.patch | 39 - .../0851-Add-BlockFace-to-BlockDamageEvent.patch | 39 - .../server/0851-Fix-NPE-on-Boat-getStatus.patch | 32 + patches/server/0852-Expand-Pose-API.patch | 51 + .../server/0852-Fix-NPE-on-Boat-getStatus.patch | 32 - patches/server/0853-Expand-Pose-API.patch | 51 - patches/server/0853-More-DragonBattle-API.patch | 91 + patches/server/0854-Add-PlayerPickItemEvent.patch | 70 + patches/server/0854-More-DragonBattle-API.patch | 91 - patches/server/0855-Add-PlayerPickItemEvent.patch | 70 - .../server/0855-Allow-trident-custom-damage.patch | 39 + .../server/0856-Allow-trident-custom-damage.patch | 39 - .../0856-Expose-hand-in-BlockCanBuildEvent.patch | 32 + .../0857-Expose-hand-in-BlockCanBuildEvent.patch | 32 - ...timize-nearest-structure-border-iteration.patch | 39 + .../0858-Implement-OfflinePlayer-isConnected.patch | 42 + ...timize-nearest-structure-border-iteration.patch | 39 - patches/server/0859-Fix-slot-desync.patch | 129 + .../0859-Implement-OfflinePlayer-isConnected.patch | 42 - ...0-Add-titleOverride-to-InventoryOpenEvent.patch | 120 + patches/server/0860-Fix-slot-desync.patch | 129 - ...1-Add-titleOverride-to-InventoryOpenEvent.patch | 120 - .../0861-Configure-sniffer-egg-hatch-time.patch | 28 + .../0862-Configure-sniffer-egg-hatch-time.patch | 28 - ...portal-proximity-check-before-entity-look.patch | 75 + ...portal-proximity-check-before-entity-look.patch | 75 - ...0863-Skip-POI-finding-if-stuck-in-vehicle.patch | 32 + ...dd-slot-sanity-checks-in-container-clicks.patch | 43 + ...0864-Skip-POI-finding-if-stuck-in-vehicle.patch | 32 - ...dd-slot-sanity-checks-in-container-clicks.patch | 43 - .../0865-Call-BlockRedstoneEvents-properly.patch | 42 + ...llow-proper-checking-of-empty-item-stacks.patch | 31 + .../0866-Call-BlockRedstoneEvents-properly.patch | 42 - ...llow-proper-checking-of-empty-item-stacks.patch | 31 - ...0867-Fix-silent-equipment-change-for-mobs.patch | 113 + ...0868-Fix-silent-equipment-change-for-mobs.patch | 113 - .../server/0868-Fix-spigot-s-Forced-Stats.patch | 54 + ...d-missing-InventoryHolders-to-inventories.patch | 314 + .../server/0869-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 + ...875-Fix-missing-map-initialize-event-call.patch | 48 + ...team-sidebar-objectives-not-being-cleared.patch | 25 - ...876-Fix-missing-map-initialize-event-call.patch | 48 - ...ty-data-when-attaching-firework-to-entity.patch | 23 + .../0877-Fix-UnsafeValues-loadAdvancement.patch | 43 + ...ty-data-when-attaching-firework-to-entity.patch | 23 - .../server/0878-Add-player-idle-duration-API.patch | 30 + .../0878-Fix-UnsafeValues-loadAdvancement.patch | 43 - .../server/0879-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 - ...0-Fix-NPE-in-SculkBloomEvent-world-access.patch | 43 + ...-itemstack-for-Player-sendEquipmentChange.patch | 19 + ...1-Fix-NPE-in-SculkBloomEvent-world-access.patch | 43 - ...-itemstack-for-Player-sendEquipmentChange.patch | 19 - patches/server/0882-Optimize-VarInts.patch | 52 + ...get-the-collision-shape-of-a-block-before.patch | 32 + patches/server/0883-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/0886-Expand-LingeringPotion-API.patch | 19 + .../server/0887-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 + .../0890-Add-UUID-attribute-modifier-API.patch | 142 + ...-Fix-several-issues-with-EntityBreedEvent.patch | 118 - .../0891-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 + ...93-Don-t-fire-sync-events-during-worldgen.patch | 208 + ...-Lazily-create-LootContext-for-criterions.patch | 30 - patches/server/0894-Add-Structure-check-API.patch | 26 + ...94-Don-t-fire-sync-events-during-worldgen.patch | 208 - patches/server/0895-Add-Structure-check-API.patch | 26 - ...taItem-getAttributeModifier-duplication-c.patch | 19 + ...taItem-getAttributeModifier-duplication-c.patch | 19 - ...896-Restore-vanilla-entity-drops-behavior.patch | 269 + .../0897-Dont-resend-blocks-on-interactions.patch | 171 + ...897-Restore-vanilla-entity-drops-behavior.patch | 269 - .../0898-Dont-resend-blocks-on-interactions.patch | 171 - patches/server/0898-add-more-scoreboard-API.patch | 79 + patches/server/0899-Improve-Registry.patch | 102 + patches/server/0899-add-more-scoreboard-API.patch | 79 - ...x-NPE-on-null-loc-for-EntityTeleportEvent.patch | 66 + patches/server/0900-Improve-Registry.patch | 102 - .../server/0901-Add-experience-points-API.patch | 73 + ...x-NPE-on-null-loc-for-EntityTeleportEvent.patch | 66 - .../server/0902-Add-drops-to-shear-events.patch | 403 + .../server/0902-Add-experience-points-API.patch | 73 - .../server/0903-Add-PlayerShieldDisableEvent.patch | 53 + .../server/0903-Add-drops-to-shear-events.patch | 403 - .../server/0904-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/0906-Fixup-NamespacedKey-handling.patch | 170 + ...handle-experience-dropping-on-block-break.patch | 94 - .../0907-Expose-LootTable-of-DecoratedPot.patch | 44 + .../server/0907-Fixup-NamespacedKey-handling.patch | 170 - .../0908-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/0910-Add-ShulkerDuplicateEvent.patch | 22 + .../server/0911-Add-ShulkerDuplicateEvent.patch | 22 - ...0911-Add-api-for-spawn-egg-texture-colors.patch | 29 + .../server/0912-Add-Lifecycle-Event-system.patch | 785 + ...0912-Add-api-for-spawn-egg-texture-colors.patch | 29 - .../server/0913-Add-Lifecycle-Event-system.patch | 785 - patches/server/0913-ItemStack-Tooltip-API.patch | 30 + ...tChunkSnapshot-includeLightData-parameter.patch | 70 + patches/server/0914-ItemStack-Tooltip-API.patch | 30 - patches/server/0915-Add-FluidState-API.patch | 208 + ...tChunkSnapshot-includeLightData-parameter.patch | 70 - patches/server/0916-Add-FluidState-API.patch | 208 - patches/server/0916-add-number-format-api.patch | 138 + patches/server/0917-add-number-format-api.patch | 138 - patches/server/0917-improve-BanList-types.patch | 32 + patches/server/0918-Expanded-Hopper-API.patch | 31 + patches/server/0918-improve-BanList-types.patch | 32 - .../0919-Add-BlockBreakProgressUpdateEvent.patch | 28 + patches/server/0919-Expanded-Hopper-API.patch | 31 - .../0920-Add-BlockBreakProgressUpdateEvent.patch | 28 - .../server/0920-Deprecate-ItemStack-setType.patch | 35 + patches/server/0921-Add-CartographyItemEvent.patch | 43 + .../server/0921-Deprecate-ItemStack-setType.patch | 35 - patches/server/0922-Add-CartographyItemEvent.patch | 43 - patches/server/0922-More-Raid-API.patch | 106 + ...boarding-message-for-initial-server-start.patch | 103 + patches/server/0923-More-Raid-API.patch | 106 - ...boarding-message-for-initial-server-start.patch | 103 - .../0924-Configurable-max-block-fluid-ticks.patch | 22 + .../0925-Configurable-max-block-fluid-ticks.patch | 22 - .../server/0925-Fix-bees-aging-inside-hives.patch | 41 + .../0926-Disable-memory-reserve-allocating.patch | 19 + .../server/0926-Fix-bees-aging-inside-hives.patch | 41 - .../0927-Disable-memory-reserve-allocating.patch | 19 - ...DamageByEntityEvent-for-unowned-wither-sk.patch | 19 + ...DamageByEntityEvent-for-unowned-wither-sk.patch | 19 - patches/server/0928-Fix-DamageSource-API.patch | 234 + patches/server/0929-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 - ...e-StackOverflowError-and-NPE-for-some-dis.patch | 306 + ...e-StackOverflowError-and-NPE-for-some-dis.patch | 306 - .../server/0931-Improve-tag-parser-handling.patch | 285 + .../server/0932-Improve-tag-parser-handling.patch | 285 - patches/server/0932-Item-Mutation-Fixes.patch | 38 + patches/server/0933-Item-Mutation-Fixes.patch | 38 - .../0933-Per-world-ticks-per-spawn-settings.patch | 35 + .../0934-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 | 171 - ...config-for-mobs-immune-to-default-effects.patch | 44 - .../server/0937-Deep-clone-nbt-tags-in-PDC.patch | 45 + .../server/0938-Deep-clone-nbt-tags-in-PDC.patch | 45 - .../0938-Support-old-UUID-format-for-NBT.patch | 63 + .../0939-Fix-shield-disable-inconsistency.patch | 22 + .../0939-Support-old-UUID-format-for-NBT.patch | 63 - .../0940-Fix-shield-disable-inconsistency.patch | 22 - ...Handle-Large-Packets-disconnecting-client.patch | 135 + patches/server/0941-Fix-ItemFlags.patch | 199 + ...Handle-Large-Packets-disconnecting-client.patch | 135 - patches/server/0942-Fix-ItemFlags.patch | 199 - .../0942-Fix-damage-modifier-inconsistencies.patch | 27 + .../0943-Fix-damage-modifier-inconsistencies.patch | 27 - ...anilla-handling-of-LivingEntity-actuallyH.patch | 63 + ...anilla-handling-of-LivingEntity-actuallyH.patch | 63 - ...improve-checking-handled-tags-in-itemmeta.patch | 887 + .../0945-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 + .../0946-Expose-hasColor-to-leather-armor.patch | 38 - ...-Added-API-to-get-player-ha-proxy-address.patch | 65 - patches/server/0947-General-ItemMeta-fixes.patch | 2168 ++ patches/server/0948-General-ItemMeta-fixes.patch | 2168 -- patches/server/0948-More-Chest-Block-API.patch | 73 + patches/server/0949-More-Chest-Block-API.patch | 73 - ...int-data-component-type-on-encoding-error.patch | 24 + .../server/0950-Brigadier-based-command-API.patch | 2819 ++ ...int-data-component-type-on-encoding-error.patch | 24 - .../server/0951-Brigadier-based-command-API.patch | 2819 -- .../server/0951-Fix-issues-with-Recipe-API.patch | 112 + .../0952-Fix-equipment-slot-and-group-API.patch | 136 + .../server/0952-Fix-issues-with-Recipe-API.patch | 112 - ...kkit-plugin-to-use-Paper-PluginLoader-API.patch | 130 + .../0953-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 - .../0957-Add-missing-fishing-event-state.patch | 26 + ...ncelling-BlockPlaceEvent-calling-onRemove.patch | 47 - .../0958-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/0960-Adopt-MaterialRerouting.patch | 134 + ...-disconnect-packet-in-phases-where-it-doe.patch | 21 - patches/server/0961-Adopt-MaterialRerouting.patch | 134 - .../server/0961-Suspicious-Effect-Entry-API.patch | 231 + .../server/0962-Suspicious-Effect-Entry-API.patch | 231 - ...962-check-if-itemstack-is-stackable-first.patch | 19 + ...-Fix-removing-recipes-from-RecipeIterator.patch | 37 + ...963-check-if-itemstack-is-stackable-first.patch | 19 - ...ble-damage-tick-when-blocking-with-shield.patch | 19 + ...-Fix-removing-recipes-from-RecipeIterator.patch | 37 - ...ble-damage-tick-when-blocking-with-shield.patch | 19 - ...move-the-experimental-smithing-inventory-.patch | 26 + ...move-the-experimental-smithing-inventory-.patch | 26 - .../0966-disable-forced-empty-world-ticks.patch | 19 + patches/server/0967-Configurable-Sand-Duping.patch | 19 + .../0967-disable-forced-empty-world-ticks.patch | 19 - ...InWorldBounds-and-getBlockState-for-inlin.patch | 101 - .../0968-Proxy-ItemStack-to-CraftItemStack.patch | 302 + ...s-in-item-frames-performance-and-bug-fixe.patch | 139 - ...C-view-accessible-directly-from-ItemStack.patch | 271 + ...twork-Manager-and-add-advanced-packet-sup.patch | 397 - ...Minecraft-commands-in-function-parsing-an.patch | 135 + .../0971-Allow-Saving-of-Oversized-Chunks.patch | 204 - .../0971-Fix-NPE-for-Jukebox-setRecord.patch | 20 + .../0972-Flat-bedrock-generator-settings.patch | 294 - patches/server/0972-fix-horse-inventories.patch | 215 + .../server/0973-Entity-Activation-Range-2.0.patch | 777 - ...ll-EntityDamageEvents-before-actuallyHurt.patch | 73 + .../server/0974-Add-ItemType-getItemRarity.patch | 23 + patches/server/0974-Anti-Xray.patch | 1664 - .../server/0975-Add-plugin-info-at-startup.patch | 64 + ...e-Velocity-compression-and-cipher-natives.patch | 389 - ...nteraction-leniency-distance-configurable.patch | 26 + ...976-Optimize-Collision-to-not-load-chunks.patch | 98 - .../0977-Fix-PickupStatus-getting-reset.patch | 65 + ...ize-GoalSelector-Goal.Flag-Set-operations.patch | 162 - ...lock-type-in-SculkSensorBlock-canActivate.patch | 19 + patches/server/0978-Optimize-Hoppers.patch | 666 - ...-for-CanPlaceOn-and-CanDestroy-NBT-values.patch | 157 + .../server/0979-Optimize-Voxel-Shape-Merging.patch | 125 - ...guration-for-horizontal-only-item-merging.patch | 28 + .../0980-Optimize-Bit-Operations-by-inlining.patch | 215 - .../0981-Add-skipping-world-symlink-scan.patch | 21 + .../server/0981-Remove-streams-from-hot-code.patch | 217 - .../0982-Add-even-more-Enchantment-API.patch | 47 + ...thfinder-Remove-Streams-Optimized-collect.patch | 136 - ...entity-type-tags-suggestions-in-selectors.patch | 154 - patches/server/0983-Leashable-API.patch | 161 + .../server/0984-Fix-CraftBukkit-drag-system.patch | 54 + ...Handle-Oversized-block-entities-in-chunks.patch | 66 - ...985-Check-distance-in-entity-interactions.patch | 69 - ...loomEvent-firing-for-block-entity-loading.patch | 39 + patches/server/0986-Configurable-Sand-Duping.patch | 19 - ...damage-lootable-item-function-from-compas.patch | 41 + .../0987-Add-enchantment-seed-update-API.patch | 39 + patches/server/0987-Properly-resend-entities.patch | 320 - ...nise-sending-chat-to-client-with-updating.patch | 27 + .../server/0988-Registry-Modification-API.patch | 1525 - .../0989-Add-registry-entry-and-builders.patch | 575 - .../0989-Fix-InventoryOpenEvent-cancellation.patch | 353 + ...0990-Fire-BlockExpEvent-on-grindstone-use.patch | 23 + .../0990-Proxy-ItemStack-to-CraftItemStack.patch | 302 - .../server/0991-Check-dead-flag-in-isAlive.patch | 29 + ...C-view-accessible-directly-from-ItemStack.patch | 271 - patches/server/0992-Add-FeatureFlag-API.patch | 429 + ...Minecraft-commands-in-function-parsing-an.patch | 135 - .../server/0993-Item-serialization-as-json.patch | 70 + .../0993-optimize-dirt-and-snow-spreading.patch | 79 - .../0994-Fix-NPE-for-Jukebox-setRecord.patch | 20 - ...-Validate-slot-in-PlayerInventory-setSlot.patch | 26 + ...ove-wall-time-unused-skip-tick-protection.patch | 163 + patches/server/0995-fix-horse-inventories.patch | 215 - ...le-pretty-printing-for-advancement-saving.patch | 22 + ...ll-EntityDamageEvents-before-actuallyHurt.patch | 73 - .../server/0997-Add-ItemType-getItemRarity.patch | 23 - ...CommandPreprocessEvent-on-signed-commands.patch | 52 + ...tWithLevels-with-enchantment-registry-set.patch | 33 + .../server/0998-Add-plugin-info-at-startup.patch | 64 - .../server/0999-Improve-entity-effect-API.patch | 154 + ...nteraction-leniency-distance-configurable.patch | 26 - patches/server/1000-Add-recipeBrewTime.patch | 181 + .../1000-Fix-PickupStatus-getting-reset.patch | 65 - .../1001-Call-bucket-events-for-cauldrons.patch | 203 + ...lock-type-in-SculkSensorBlock-canActivate.patch | 19 - ...-for-CanPlaceOn-and-CanDestroy-NBT-values.patch | 157 - .../1002-Add-PlayerInsertLecternBookEvent.patch | 36 + ...guration-for-horizontal-only-item-merging.patch | 28 - .../1003-Void-damage-configuration-API.patch | 93 + patches/server/1004-Add-Offline-PDC-API.patch | 45 + .../1004-Add-skipping-world-symlink-scan.patch | 21 - ...vilView-bypassEnchantmentLevelRestriction.patch | 53 + .../1005-Add-even-more-Enchantment-API.patch | 47 - ...06-Add-proper-async-player-disconnections.patch | 168 + patches/server/1006-Leashable-API.patch | 161 - .../server/1007-Fix-CraftBukkit-drag-system.patch | 54 - .../1007-Separate-dimensiondata-executor.patch | 62 + ...Always-send-Banner-patterns-to-the-client.patch | 42 + ...loomEvent-firing-for-block-entity-loading.patch | 39 - .../server/1009-API-for-checking-sent-chunks.patch | 45 + ...damage-lootable-item-function-from-compas.patch | 41 - .../1010-Add-enchantment-seed-update-API.patch | 39 - .../1010-Fix-CraftWorld-isChunkGenerated.patch | 44 + ...d-startup-flag-to-disable-gamerule-limits.patch | 69 + ...nise-sending-chat-to-client-with-updating.patch | 27 - patches/server/1012-Bundle-spark.patch | 401 + .../1012-Fix-InventoryOpenEvent-cancellation.patch | 353 - ...s-with-certain-tasks-not-processing-durin.patch | 46 + ...1013-Fire-BlockExpEvent-on-grindstone-use.patch | 23 - ...1014-Allow-using-old-ender-pearl-behavior.patch | 62 + .../server/1014-Check-dead-flag-in-isAlive.patch | 29 - patches/server/1015-Add-FeatureFlag-API.patch | 429 - .../1015-Block-Enderpearl-Travel-Exploit.patch | 49 + ...stencies-in-dispense-events-regarding-sta.patch | 432 + patches/server/1016-Tag-Lifecycle-Events.patch | 595 - patches/server/1017-Correct-update-cursor.patch | 42 + .../server/1017-Item-serialization-as-json.patch | 73 - ...layer-onEntityRemove-for-all-online-playe.patch | 19 + ...-Validate-slot-in-PlayerInventory-setSlot.patch | 26 - ...ove-performance-of-RecipeMap-removeRecipe.patch | 89 + ...ove-wall-time-unused-skip-tick-protection.patch | 163 - ...le-pretty-printing-for-advancement-saving.patch | 22 - ...-done-in-CraftMapCanvas.drawImage-by-limi.patch | 75 + ...CommandPreprocessEvent-on-signed-commands.patch | 52 - ...ncorrect-invulnerability-damage-reduction.patch | 115 + ...tWithLevels-with-enchantment-registry-set.patch | 33 - ...-when-EntityResurrectEvent-is-uncancelled.patch | 23 + ...23-API-to-check-if-the-server-is-sleeping.patch | 37 + .../server/1023-Improve-entity-effect-API.patch | 154 - .../1024-API-to-allow-disallow-tick-sleeping.patch | 67 + patches/server/1024-Add-recipeBrewTime.patch | 181 - .../1025-Call-bucket-events-for-cauldrons.patch | 203 - .../1025-Configurable-Entity-Despawn-Time.patch | 39 + .../1026-Add-PlayerInsertLecternBookEvent.patch | 36 - patches/server/1026-Expanded-Art-API.patch | 33 + ...t-to-find-spawn-position-if-there-isn-t-a.patch | 28 + .../1027-Void-damage-configuration-API.patch | 93 - patches/server/1028-Add-Offline-PDC-API.patch | 45 - .../server/1028-Registry-Modification-API.patch | 1523 + ...vilView-bypassEnchantmentLevelRestriction.patch | 53 - .../1029-Add-registry-entry-and-builders.patch | 574 + ...30-Add-proper-async-player-disconnections.patch | 168 - patches/server/1030-Tag-Lifecycle-Events.patch | 595 + ...InWorldBounds-and-getBlockState-for-inlin.patch | 99 + .../1032-Separate-dimensiondata-executor.patch | 62 - ...Always-send-Banner-patterns-to-the-client.patch | 42 - ...s-in-item-frames-performance-and-bug-fixe.patch | 137 + ...twork-Manager-and-add-advanced-packet-sup.patch | 395 + .../server/1034-Rewrite-dataconverter-system.patch | 30792 ---------------- .../1035-Allow-Saving-of-Oversized-Chunks.patch | 202 + .../1035-Moonrise-optimisation-patches.patch | 36072 ------------------ .../1036-Flat-bedrock-generator-settings.patch | 292 + ...chunk-data-to-disk-if-it-serializes-witho.patch | 129 - .../server/1037-API-for-checking-sent-chunks.patch | 46 - .../server/1037-Entity-Activation-Range-2.0.patch | 775 + patches/server/1038-Anti-Xray.patch | 1663 + .../1038-Fix-CraftWorld-isChunkGenerated.patch | 44 - ...d-startup-flag-to-disable-gamerule-limits.patch | 66 - ...e-Velocity-compression-and-cipher-natives.patch | 387 + .../server/1040-Improved-Watchdog-Support.patch | 475 - ...040-Optimize-Collision-to-not-load-chunks.patch | 96 + ...Detail-more-information-in-watchdog-dumps.patch | 297 - ...ize-GoalSelector-Goal.Flag-Set-operations.patch | 171 + .../1042-Entity-load-save-limit-per-chunk.patch | 81 - patches/server/1042-Optimize-Hoppers.patch | 664 + ...recalculate-regionfile-header-if-it-is-co.patch | 744 - .../server/1043-Optimize-Voxel-Shape-Merging.patch | 123 + patches/server/1044-Bundle-spark.patch | 401 - .../1044-Optimize-Bit-Operations-by-inlining.patch | 213 + .../1045-Improve-performance-of-mass-crafts.patch | 94 - .../server/1045-Remove-streams-from-hot-code.patch | 215 + .../1046-Incremental-chunk-and-player-saving.patch | 134 - ...thfinder-Remove-Streams-Optimized-collect.patch | 134 + ...entity-type-tags-suggestions-in-selectors.patch | 152 + .../server/1047-Optimise-general-POI-access.patch | 1069 - ...tracker-desync-when-new-players-are-added.patch | 107 - ...Handle-Oversized-block-entities-in-chunks.patch | 64 + ...049-Check-distance-in-entity-interactions.patch | 68 + patches/server/1049-Lag-compensation-ticks.patch | 131 - ...llision-checking-in-player-move-packet-ha.patch | 170 - patches/server/1050-Properly-resend-entities.patch | 318 + .../1051-Optional-per-player-mob-spawns.patch | 233 - .../1051-optimize-dirt-and-snow-spreading.patch | 78 + ...celling-PreCreatureSpawnEvent-with-per-pl.patch | 89 - ...timise-getChunkAt-calls-for-loaded-chunks.patch | 60 + ...s-with-certain-tasks-not-processing-durin.patch | 46 - .../server/1053-Rewrite-dataconverter-system.patch | 30804 ++++++++++++++++ ...1054-Allow-using-old-ender-pearl-behavior.patch | 62 - .../1054-Moonrise-optimisation-patches.patch | 36349 +++++++++++++++++++ .../1055-Block-Enderpearl-Travel-Exploit.patch | 49 - ...chunk-data-to-disk-if-it-serializes-witho.patch | 129 + ...stencies-in-dispense-events-regarding-sta.patch | 432 - .../server/1056-Improved-Watchdog-Support.patch | 473 + patches/server/1057-Correct-update-cursor.patch | 42 - ...Detail-more-information-in-watchdog-dumps.patch | 295 + ...layer-onEntityRemove-for-all-online-playe.patch | 19 - .../1058-Entity-load-save-limit-per-chunk.patch | 81 + ...recalculate-regionfile-header-if-it-is-co.patch | 742 + .../1059-Eigencraft-redstone-implementation.patch | 1099 - ...ove-performance-of-RecipeMap-removeRecipe.patch | 89 - .../1060-Improve-performance-of-mass-crafts.patch | 92 + .../1061-Incremental-chunk-and-player-saving.patch | 133 + ...-done-in-CraftMapCanvas.drawImage-by-limi.patch | 75 - ...Alternate-Current-redstone-implementation.patch | 2452 -- .../server/1062-Optimise-general-POI-access.patch | 1067 + ...tracker-desync-when-new-players-are-added.patch | 105 + ...ncorrect-invulnerability-damage-reduction.patch | 115 - ...-when-EntityResurrectEvent-is-uncancelled.patch | 23 - patches/server/1064-Lag-compensation-ticks.patch | 129 + ...65-API-to-check-if-the-server-is-sleeping.patch | 37 - ...llision-checking-in-player-move-packet-ha.patch | 168 + .../1066-API-to-allow-disallow-tick-sleeping.patch | 67 - .../1066-Optional-per-player-mob-spawns.patch | 232 + .../1067-Configurable-Entity-Despawn-Time.patch | 39 - ...celling-PreCreatureSpawnEvent-with-per-pl.patch | 89 + .../1068-Eigencraft-redstone-implementation.patch | 1097 + patches/server/1068-Expanded-Art-API.patch | 33 - ...Alternate-Current-redstone-implementation.patch | 2450 ++ ...t-to-find-spawn-position-if-there-isn-t-a.patch | 28 - ...0-Improve-exact-choice-recipe-ingredients.patch | 2 - patches/server/1071-Implement-chunk-view-API.patch | 48 + 1525 files changed, 145223 insertions(+), 145202 deletions(-) create mode 100644 patches/server/0308-Add-debug-for-sync-chunk-loads.patch delete mode 100644 patches/server/0308-Optimise-getChunkAt-calls-for-loaded-chunks.patch delete mode 100644 patches/server/0309-Add-debug-for-sync-chunk-loads.patch create mode 100644 patches/server/0309-Improve-java-version-check.patch create mode 100644 patches/server/0310-Add-ThrownEggHatchEvent.patch delete mode 100644 patches/server/0310-Improve-java-version-check.patch delete mode 100644 patches/server/0311-Add-ThrownEggHatchEvent.patch create mode 100644 patches/server/0311-Entity-Jump-API.patch create mode 100644 patches/server/0312-Add-option-to-nerf-pigmen-from-nether-portals.patch delete mode 100644 patches/server/0312-Entity-Jump-API.patch delete mode 100644 patches/server/0313-Add-option-to-nerf-pigmen-from-nether-portals.patch create mode 100644 patches/server/0313-Make-the-GUI-graph-fancier.patch delete mode 100644 patches/server/0314-Make-the-GUI-graph-fancier.patch create mode 100644 patches/server/0314-add-hand-to-BlockMultiPlaceEvent.patch create mode 100644 patches/server/0315-Validate-tripwire-hook-placement-before-update.patch delete mode 100644 patches/server/0315-add-hand-to-BlockMultiPlaceEvent.patch create mode 100644 patches/server/0316-Add-option-to-allow-iron-golems-to-spawn-in-air.patch delete mode 100644 patches/server/0316-Validate-tripwire-hook-placement-before-update.patch delete mode 100644 patches/server/0317-Add-option-to-allow-iron-golems-to-spawn-in-air.patch create mode 100644 patches/server/0317-Configurable-chance-of-villager-zombie-infection.patch delete mode 100644 patches/server/0318-Configurable-chance-of-villager-zombie-infection.patch create mode 100644 patches/server/0318-Optimise-Chunk-getFluid.patch delete mode 100644 patches/server/0319-Optimise-Chunk-getFluid.patch create mode 100644 patches/server/0319-Set-spigots-verbose-world-setting-to-false-by-def.patch create mode 100644 patches/server/0320-Add-tick-times-API-and-mspt-command.patch delete mode 100644 patches/server/0320-Set-spigots-verbose-world-setting-to-false-by-def.patch delete mode 100644 patches/server/0321-Add-tick-times-API-and-mspt-command.patch create mode 100644 patches/server/0321-Expose-MinecraftServer-isRunning.patch create mode 100644 patches/server/0322-Add-Raw-Byte-ItemStack-Serialization.patch delete mode 100644 patches/server/0322-Expose-MinecraftServer-isRunning.patch delete mode 100644 patches/server/0323-Add-Raw-Byte-ItemStack-Serialization.patch create mode 100644 patches/server/0323-Pillager-patrol-spawn-settings-and-per-player-option.patch delete mode 100644 patches/server/0324-Pillager-patrol-spawn-settings-and-per-player-option.patch create mode 100644 patches/server/0324-Remote-Connections-shouldn-t-hold-up-shutdown.patch create mode 100644 patches/server/0325-Do-not-allow-Vexes-to-load-chunks.patch delete mode 100644 patches/server/0325-Remote-Connections-shouldn-t-hold-up-shutdown.patch delete mode 100644 patches/server/0326-Do-not-allow-Vexes-to-load-chunks.patch create mode 100644 patches/server/0326-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch create mode 100644 patches/server/0327-Don-t-tick-dead-players.patch delete mode 100644 patches/server/0327-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch create mode 100644 patches/server/0328-Dead-Player-s-shouldn-t-be-able-to-move.patch delete mode 100644 patches/server/0328-Don-t-tick-dead-players.patch delete mode 100644 patches/server/0329-Dead-Player-s-shouldn-t-be-able-to-move.patch create mode 100644 patches/server/0329-Don-t-move-existing-players-to-world-spawn.patch delete mode 100644 patches/server/0330-Don-t-move-existing-players-to-world-spawn.patch create mode 100644 patches/server/0330-Optimize-Pathfinding.patch delete mode 100644 patches/server/0331-Optimize-Pathfinding.patch create mode 100644 patches/server/0331-Reduce-Either-Optional-allocation.patch delete mode 100644 patches/server/0332-Reduce-Either-Optional-allocation.patch create mode 100644 patches/server/0332-Reduce-memory-footprint-of-CompoundTag.patch create mode 100644 patches/server/0333-Prevent-opening-inventories-when-frozen.patch delete mode 100644 patches/server/0333-Reduce-memory-footprint-of-CompoundTag.patch create mode 100644 patches/server/0334-Don-t-run-entity-collision-code-if-not-needed.patch delete mode 100644 patches/server/0334-Prevent-opening-inventories-when-frozen.patch delete mode 100644 patches/server/0335-Don-t-run-entity-collision-code-if-not-needed.patch create mode 100644 patches/server/0335-Implement-Player-Client-Options-API.patch create mode 100644 patches/server/0336-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch delete mode 100644 patches/server/0336-Implement-Player-Client-Options-API.patch delete mode 100644 patches/server/0337-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch create mode 100644 patches/server/0337-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch delete mode 100644 patches/server/0338-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch create mode 100644 patches/server/0338-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch create mode 100644 patches/server/0339-Add-PlayerAttackEntityCooldownResetEvent.patch delete mode 100644 patches/server/0339-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch delete mode 100644 patches/server/0340-Add-PlayerAttackEntityCooldownResetEvent.patch create mode 100644 patches/server/0340-Don-t-fire-BlockFade-on-worldgen-threads.patch create mode 100644 patches/server/0341-Add-phantom-creative-and-insomniac-controls.patch delete mode 100644 patches/server/0341-Don-t-fire-BlockFade-on-worldgen-threads.patch delete mode 100644 patches/server/0342-Add-phantom-creative-and-insomniac-controls.patch create mode 100644 patches/server/0342-Fix-item-duplication-and-teleport-issues.patch delete mode 100644 patches/server/0343-Fix-item-duplication-and-teleport-issues.patch create mode 100644 patches/server/0343-Villager-Restocks-API.patch create mode 100644 patches/server/0344-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch delete mode 100644 patches/server/0344-Villager-Restocks-API.patch delete mode 100644 patches/server/0345-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch create mode 100644 patches/server/0345-misc-debugging-dumps.patch create mode 100644 patches/server/0346-Prevent-teleporting-dead-entities.patch delete mode 100644 patches/server/0346-misc-debugging-dumps.patch create mode 100644 patches/server/0347-Implement-Mob-Goal-API.patch delete mode 100644 patches/server/0347-Prevent-teleporting-dead-entities.patch create mode 100644 patches/server/0348-Add-villager-reputation-API.patch delete mode 100644 patches/server/0348-Implement-Mob-Goal-API.patch delete mode 100644 patches/server/0349-Add-villager-reputation-API.patch create mode 100644 patches/server/0349-ExperienceOrb-merging-stacking-API-and-fixes.patch delete mode 100644 patches/server/0350-ExperienceOrb-merging-stacking-API-and-fixes.patch create mode 100644 patches/server/0350-Fix-PotionEffect-ignores-icon-flag.patch delete mode 100644 patches/server/0351-Fix-PotionEffect-ignores-icon-flag.patch create mode 100644 patches/server/0351-Potential-bed-API.patch delete mode 100644 patches/server/0352-Potential-bed-API.patch create mode 100644 patches/server/0352-Wait-for-Async-Tasks-during-shutdown.patch create mode 100644 patches/server/0353-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch delete mode 100644 patches/server/0353-Wait-for-Async-Tasks-during-shutdown.patch create mode 100644 patches/server/0354-Add-option-for-console-having-all-permissions.patch delete mode 100644 patches/server/0354-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch delete mode 100644 patches/server/0355-Add-option-for-console-having-all-permissions.patch create mode 100644 patches/server/0355-Fix-villager-trading-demand-MC-163962.patch delete mode 100644 patches/server/0356-Fix-villager-trading-demand-MC-163962.patch create mode 100644 patches/server/0356-Maps-shouldn-t-load-chunks.patch delete mode 100644 patches/server/0357-Maps-shouldn-t-load-chunks.patch create mode 100644 patches/server/0357-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch create mode 100644 patches/server/0358-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch delete mode 100644 patches/server/0358-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch delete mode 100644 patches/server/0359-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch create mode 100644 patches/server/0359-Fix-piston-physics-inconsistency-MC-188840.patch create mode 100644 patches/server/0360-Fix-missing-chunks-due-to-integer-overflow.patch delete mode 100644 patches/server/0360-Fix-piston-physics-inconsistency-MC-188840.patch delete mode 100644 patches/server/0361-Fix-missing-chunks-due-to-integer-overflow.patch create mode 100644 patches/server/0361-Prevent-position-desync-causing-tp-exploit.patch create mode 100644 patches/server/0362-Inventory-getHolder-method-without-block-snapshot.patch delete mode 100644 patches/server/0362-Prevent-position-desync-causing-tp-exploit.patch create mode 100644 patches/server/0363-Add-PlayerRecipeBookClickEvent.patch delete mode 100644 patches/server/0363-Inventory-getHolder-method-without-block-snapshot.patch delete mode 100644 patches/server/0364-Add-PlayerRecipeBookClickEvent.patch create mode 100644 patches/server/0364-Hide-sync-chunk-writes-behind-flag.patch create mode 100644 patches/server/0365-Add-permission-for-command-blocks.patch delete mode 100644 patches/server/0365-Hide-sync-chunk-writes-behind-flag.patch delete mode 100644 patches/server/0366-Add-permission-for-command-blocks.patch create mode 100644 patches/server/0366-Ensure-Entity-position-and-AABB-are-never-invalid.patch delete mode 100644 patches/server/0367-Ensure-Entity-position-and-AABB-are-never-invalid.patch create mode 100644 patches/server/0367-Fix-Per-World-Difficulty-Remembering-Difficulty.patch delete mode 100644 patches/server/0368-Fix-Per-World-Difficulty-Remembering-Difficulty.patch create mode 100644 patches/server/0368-Paper-dumpitem-command.patch create mode 100644 patches/server/0369-Improve-Legacy-Component-serialization-size.patch delete mode 100644 patches/server/0369-Paper-dumpitem-command.patch create mode 100644 patches/server/0370-Add-BlockStateMeta-clearBlockState.patch delete mode 100644 patches/server/0370-Improve-Legacy-Component-serialization-size.patch delete mode 100644 patches/server/0371-Add-BlockStateMeta-clearBlockState.patch create mode 100644 patches/server/0371-Convert-legacy-attributes-in-Item-Meta.patch delete mode 100644 patches/server/0372-Convert-legacy-attributes-in-Item-Meta.patch create mode 100644 patches/server/0372-Do-not-accept-invalid-client-settings.patch delete mode 100644 patches/server/0373-Do-not-accept-invalid-client-settings.patch create mode 100644 patches/server/0373-Improve-fix-EntityTargetLivingEntityEvent.patch create mode 100644 patches/server/0374-Add-entity-liquid-API.patch delete mode 100644 patches/server/0374-Improve-fix-EntityTargetLivingEntityEvent.patch create mode 100644 patches/server/0375-Add-PrepareResultEvent.patch delete mode 100644 patches/server/0375-Add-entity-liquid-API.patch delete mode 100644 patches/server/0376-Add-PrepareResultEvent.patch create mode 100644 patches/server/0376-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch delete mode 100644 patches/server/0377-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch create mode 100644 patches/server/0377-Fix-arrows-never-despawning-MC-125757.patch delete mode 100644 patches/server/0378-Fix-arrows-never-despawning-MC-125757.patch create mode 100644 patches/server/0378-Thread-Safe-Vanilla-Command-permission-checking.patch create mode 100644 patches/server/0379-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch delete mode 100644 patches/server/0379-Thread-Safe-Vanilla-Command-permission-checking.patch delete mode 100644 patches/server/0380-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch create mode 100644 patches/server/0380-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch create mode 100644 patches/server/0381-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch delete mode 100644 patches/server/0381-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch delete mode 100644 patches/server/0382-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch create mode 100644 patches/server/0382-Optimize-NetworkManager-Exception-Handling.patch create mode 100644 patches/server/0383-Fix-some-rails-connecting-improperly.patch delete mode 100644 patches/server/0383-Optimize-NetworkManager-Exception-Handling.patch create mode 100644 patches/server/0384-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch delete mode 100644 patches/server/0384-Fix-some-rails-connecting-improperly.patch create mode 100644 patches/server/0385-Brand-support.patch delete mode 100644 patches/server/0385-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch create mode 100644 patches/server/0386-Add-playPickupItemAnimation-to-LivingEntity.patch delete mode 100644 patches/server/0386-Brand-support.patch delete mode 100644 patches/server/0387-Add-playPickupItemAnimation-to-LivingEntity.patch create mode 100644 patches/server/0387-Don-t-require-FACING-data.patch delete mode 100644 patches/server/0388-Don-t-require-FACING-data.patch create mode 100644 patches/server/0388-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch create mode 100644 patches/server/0389-Add-moon-phase-API.patch delete mode 100644 patches/server/0389-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch delete mode 100644 patches/server/0390-Add-moon-phase-API.patch create mode 100644 patches/server/0390-Do-not-let-the-server-load-chunks-from-newer-version.patch delete mode 100644 patches/server/0391-Do-not-let-the-server-load-chunks-from-newer-version.patch create mode 100644 patches/server/0391-Prevent-headless-pistons-from-being-created.patch create mode 100644 patches/server/0392-Add-BellRingEvent.patch delete mode 100644 patches/server/0392-Prevent-headless-pistons-from-being-created.patch delete mode 100644 patches/server/0393-Add-BellRingEvent.patch create mode 100644 patches/server/0393-Add-zombie-targets-turtle-egg-config.patch delete mode 100644 patches/server/0394-Add-zombie-targets-turtle-egg-config.patch create mode 100644 patches/server/0394-Buffer-joins-to-world.patch delete mode 100644 patches/server/0395-Buffer-joins-to-world.patch create mode 100644 patches/server/0395-Fix-hex-colors-not-working-in-some-kick-messages.patch create mode 100644 patches/server/0396-Add-more-Evoker-API.patch delete mode 100644 patches/server/0396-Fix-hex-colors-not-working-in-some-kick-messages.patch create mode 100644 patches/server/0397-Add-methods-to-get-translation-keys.patch delete mode 100644 patches/server/0397-Add-more-Evoker-API.patch delete mode 100644 patches/server/0398-Add-methods-to-get-translation-keys.patch create mode 100644 patches/server/0398-Create-HoverEvent-from-ItemStack-Entity.patch create mode 100644 patches/server/0399-Cache-block-data-strings.patch delete mode 100644 patches/server/0399-Create-HoverEvent-from-ItemStack-Entity.patch delete mode 100644 patches/server/0400-Cache-block-data-strings.patch create mode 100644 patches/server/0400-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch create mode 100644 patches/server/0401-Add-additional-open-container-api-to-HumanEntity.patch delete mode 100644 patches/server/0401-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch delete mode 100644 patches/server/0402-Add-additional-open-container-api-to-HumanEntity.patch create mode 100644 patches/server/0402-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch delete mode 100644 patches/server/0403-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch create mode 100644 patches/server/0403-Extend-block-drop-capture-to-capture-all-items-added.patch create mode 100644 patches/server/0404-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch delete mode 100644 patches/server/0404-Extend-block-drop-capture-to-capture-all-items-added.patch delete mode 100644 patches/server/0405-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch create mode 100644 patches/server/0405-Lazily-track-plugin-scoreboards-by-default.patch create mode 100644 patches/server/0406-Entity-isTicking.patch delete mode 100644 patches/server/0406-Lazily-track-plugin-scoreboards-by-default.patch delete mode 100644 patches/server/0407-Entity-isTicking.patch create mode 100644 patches/server/0407-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch create mode 100644 patches/server/0408-Fix-Concurrency-issue-in-ShufflingList.patch delete mode 100644 patches/server/0408-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch delete mode 100644 patches/server/0409-Fix-Concurrency-issue-in-ShufflingList.patch create mode 100644 patches/server/0409-Reset-Ender-Crystals-on-Dragon-Spawn.patch create mode 100644 patches/server/0410-Fix-for-large-move-vectors-crashing-server.patch delete mode 100644 patches/server/0410-Reset-Ender-Crystals-on-Dragon-Spawn.patch delete mode 100644 patches/server/0411-Fix-for-large-move-vectors-crashing-server.patch create mode 100644 patches/server/0411-Optimise-getType-calls.patch delete mode 100644 patches/server/0412-Optimise-getType-calls.patch create mode 100644 patches/server/0412-Villager-resetOffers.patch create mode 100644 patches/server/0413-Retain-block-place-order-when-capturing-blockstates.patch delete mode 100644 patches/server/0413-Villager-resetOffers.patch create mode 100644 patches/server/0414-Fix-item-locations-dropped-from-campfires.patch delete mode 100644 patches/server/0414-Retain-block-place-order-when-capturing-blockstates.patch create mode 100644 patches/server/0415-Fix-bell-block-entity-memory-leak.patch delete mode 100644 patches/server/0415-Fix-item-locations-dropped-from-campfires.patch create mode 100644 patches/server/0416-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch delete mode 100644 patches/server/0416-Fix-bell-block-entity-memory-leak.patch create mode 100644 patches/server/0417-Add-getOfflinePlayerIfCached-String.patch delete mode 100644 patches/server/0417-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch delete mode 100644 patches/server/0418-Add-getOfflinePlayerIfCached-String.patch create mode 100644 patches/server/0418-Add-ignore-discounts-API.patch delete mode 100644 patches/server/0419-Add-ignore-discounts-API.patch create mode 100644 patches/server/0419-Toggle-for-removing-existing-dragon.patch create mode 100644 patches/server/0420-Fix-client-lag-on-advancement-loading.patch delete mode 100644 patches/server/0420-Toggle-for-removing-existing-dragon.patch delete mode 100644 patches/server/0421-Fix-client-lag-on-advancement-loading.patch create mode 100644 patches/server/0421-Item-no-age-no-player-pickup.patch create mode 100644 patches/server/0422-Beacon-API-custom-effect-ranges.patch delete mode 100644 patches/server/0422-Item-no-age-no-player-pickup.patch create mode 100644 patches/server/0423-Add-API-for-quit-reason.patch delete mode 100644 patches/server/0423-Beacon-API-custom-effect-ranges.patch delete mode 100644 patches/server/0424-Add-API-for-quit-reason.patch create mode 100644 patches/server/0424-Add-Wandering-Trader-spawn-rate-config-options.patch create mode 100644 patches/server/0425-Add-Destroy-Speed-API.patch delete mode 100644 patches/server/0425-Add-Wandering-Trader-spawn-rate-config-options.patch delete mode 100644 patches/server/0426-Add-Destroy-Speed-API.patch create mode 100644 patches/server/0426-Fix-Player-spawnParticle-x-y-z-precision-loss.patch create mode 100644 patches/server/0427-Add-LivingEntity-clearActiveItem.patch delete mode 100644 patches/server/0427-Fix-Player-spawnParticle-x-y-z-precision-loss.patch delete mode 100644 patches/server/0428-Add-LivingEntity-clearActiveItem.patch create mode 100644 patches/server/0428-Add-PlayerItemCooldownEvent.patch delete mode 100644 patches/server/0429-Add-PlayerItemCooldownEvent.patch create mode 100644 patches/server/0429-Significantly-improve-performance-of-the-end-generat.patch create mode 100644 patches/server/0430-More-lightning-API.patch delete mode 100644 patches/server/0430-Significantly-improve-performance-of-the-end-generat.patch create mode 100644 patches/server/0431-Climbing-should-not-bypass-cramming-gamerule.patch delete mode 100644 patches/server/0431-More-lightning-API.patch create mode 100644 patches/server/0432-Add-missing-default-perms-for-commands.patch delete mode 100644 patches/server/0432-Climbing-should-not-bypass-cramming-gamerule.patch create mode 100644 patches/server/0433-Add-PlayerShearBlockEvent.patch delete mode 100644 patches/server/0433-Add-missing-default-perms-for-commands.patch delete mode 100644 patches/server/0434-Add-PlayerShearBlockEvent.patch create mode 100644 patches/server/0434-Limit-recipe-packets.patch create mode 100644 patches/server/0435-Fix-CraftSound-backwards-compatibility.patch delete mode 100644 patches/server/0435-Limit-recipe-packets.patch delete mode 100644 patches/server/0436-Fix-CraftSound-backwards-compatibility.patch create mode 100644 patches/server/0436-Player-Chunk-Load-Unload-Events.patch create mode 100644 patches/server/0437-Optimize-Dynamic-get-Missing-Keys.patch delete mode 100644 patches/server/0437-Player-Chunk-Load-Unload-Events.patch create mode 100644 patches/server/0438-Expose-LivingEntity-hurt-direction.patch delete mode 100644 patches/server/0438-Optimize-Dynamic-get-Missing-Keys.patch create mode 100644 patches/server/0439-Add-OBSTRUCTED-reason-to-BedEnterResult.patch delete mode 100644 patches/server/0439-Expose-LivingEntity-hurt-direction.patch delete mode 100644 patches/server/0440-Add-OBSTRUCTED-reason-to-BedEnterResult.patch create mode 100644 patches/server/0440-Fix-crash-from-invalid-ingredient-lists-in-VillagerA.patch create mode 100644 patches/server/0441-Add-TargetHitEvent.patch delete mode 100644 patches/server/0441-Fix-crash-from-invalid-ingredient-lists-in-VillagerA.patch delete mode 100644 patches/server/0442-Add-TargetHitEvent.patch create mode 100644 patches/server/0442-MC-4-Fix-item-position-desync.patch create mode 100644 patches/server/0443-Additional-Block-Material-API.patch delete mode 100644 patches/server/0443-MC-4-Fix-item-position-desync.patch create mode 100644 patches/server/0444-API-to-get-Material-from-Boats-and-Minecarts.patch delete mode 100644 patches/server/0444-Additional-Block-Material-API.patch delete mode 100644 patches/server/0445-API-to-get-Material-from-Boats-and-Minecarts.patch create mode 100644 patches/server/0445-Allow-disabling-mob-spawner-spawn-egg-transformation.patch delete mode 100644 patches/server/0446-Allow-disabling-mob-spawner-spawn-egg-transformation.patch create mode 100644 patches/server/0446-Fix-Not-a-string-Map-Conversion-spam.patch create mode 100644 patches/server/0447-Add-PlayerFlowerPotManipulateEvent.patch delete mode 100644 patches/server/0447-Fix-Not-a-string-Map-Conversion-spam.patch delete mode 100644 patches/server/0448-Add-PlayerFlowerPotManipulateEvent.patch create mode 100644 patches/server/0448-Fix-interact-event-not-being-called-sometimes.patch delete mode 100644 patches/server/0449-Fix-interact-event-not-being-called-sometimes.patch create mode 100644 patches/server/0449-Zombie-API-breaking-doors.patch create mode 100644 patches/server/0450-Fix-nerfed-slime-when-splitting.patch delete mode 100644 patches/server/0450-Zombie-API-breaking-doors.patch create mode 100644 patches/server/0451-Add-EntityLoadCrossbowEvent.patch delete mode 100644 patches/server/0451-Fix-nerfed-slime-when-splitting.patch delete mode 100644 patches/server/0452-Add-EntityLoadCrossbowEvent.patch create mode 100644 patches/server/0452-Add-WorldGameRuleChangeEvent.patch create mode 100644 patches/server/0453-Add-ServerResourcesReloadedEvent.patch delete mode 100644 patches/server/0453-Add-WorldGameRuleChangeEvent.patch delete mode 100644 patches/server/0454-Add-ServerResourcesReloadedEvent.patch create mode 100644 patches/server/0454-Add-world-settings-for-mobs-picking-up-loot.patch create mode 100644 patches/server/0455-Add-BlockFailedDispenseEvent.patch delete mode 100644 patches/server/0455-Add-world-settings-for-mobs-picking-up-loot.patch delete mode 100644 patches/server/0456-Add-BlockFailedDispenseEvent.patch create mode 100644 patches/server/0456-Add-PlayerLecternPageChangeEvent.patch delete mode 100644 patches/server/0457-Add-PlayerLecternPageChangeEvent.patch create mode 100644 patches/server/0457-Add-PlayerLoomPatternSelectEvent.patch delete mode 100644 patches/server/0458-Add-PlayerLoomPatternSelectEvent.patch create mode 100644 patches/server/0458-Configurable-door-breaking-difficulty.patch delete mode 100644 patches/server/0459-Configurable-door-breaking-difficulty.patch create mode 100644 patches/server/0459-Empty-commands-shall-not-be-dispatched.patch delete mode 100644 patches/server/0460-Empty-commands-shall-not-be-dispatched.patch create mode 100644 patches/server/0460-Remove-stale-POIs.patch create mode 100644 patches/server/0461-Fix-villager-boat-exploit.patch delete mode 100644 patches/server/0461-Remove-stale-POIs.patch create mode 100644 patches/server/0462-Add-sendOpLevel-API.patch delete mode 100644 patches/server/0462-Fix-villager-boat-exploit.patch create mode 100644 patches/server/0463-Add-RegistryAccess-for-managing-Registries.patch delete mode 100644 patches/server/0463-Add-sendOpLevel-API.patch delete mode 100644 patches/server/0464-Add-RegistryAccess-for-managing-Registries.patch create mode 100644 patches/server/0464-Add-StructuresLocateEvent.patch delete mode 100644 patches/server/0465-Add-StructuresLocateEvent.patch create mode 100644 patches/server/0465-Collision-option-for-requiring-a-player-participant.patch delete mode 100644 patches/server/0466-Collision-option-for-requiring-a-player-participant.patch create mode 100644 patches/server/0466-Return-chat-component-with-empty-text-instead-of-thr.patch create mode 100644 patches/server/0467-Make-schedule-command-per-world.patch delete mode 100644 patches/server/0467-Return-chat-component-with-empty-text-instead-of-thr.patch create mode 100644 patches/server/0468-Configurable-max-leash-distance.patch delete mode 100644 patches/server/0468-Make-schedule-command-per-world.patch create mode 100644 patches/server/0469-Add-BlockPreDispenseEvent.patch delete mode 100644 patches/server/0469-Configurable-max-leash-distance.patch delete mode 100644 patches/server/0470-Add-BlockPreDispenseEvent.patch create mode 100644 patches/server/0470-Add-PlayerChangeBeaconEffectEvent.patch delete mode 100644 patches/server/0471-Add-PlayerChangeBeaconEffectEvent.patch create mode 100644 patches/server/0471-Add-toggle-for-always-placing-the-dragon-egg.patch create mode 100644 patches/server/0472-Add-PlayerStonecutterRecipeSelectEvent.patch delete mode 100644 patches/server/0472-Add-toggle-for-always-placing-the-dragon-egg.patch delete mode 100644 patches/server/0473-Add-PlayerStonecutterRecipeSelectEvent.patch create mode 100644 patches/server/0473-Expand-EntityUnleashEvent.patch delete mode 100644 patches/server/0474-Expand-EntityUnleashEvent.patch create mode 100644 patches/server/0474-Reset-shield-blocking-on-dimension-change.patch create mode 100644 patches/server/0475-Add-DragonEggFormEvent.patch delete mode 100644 patches/server/0475-Reset-shield-blocking-on-dimension-change.patch delete mode 100644 patches/server/0476-Add-DragonEggFormEvent.patch create mode 100644 patches/server/0476-Add-EntityMoveEvent.patch delete mode 100644 patches/server/0477-Add-EntityMoveEvent.patch create mode 100644 patches/server/0477-added-option-to-disable-pathfinding-updates-on-block.patch create mode 100644 patches/server/0478-Inline-shift-direction-fields.patch delete mode 100644 patches/server/0478-added-option-to-disable-pathfinding-updates-on-block.patch create mode 100644 patches/server/0479-Allow-adding-items-to-BlockDropItemEvent.patch delete mode 100644 patches/server/0479-Inline-shift-direction-fields.patch create mode 100644 patches/server/0480-Add-getMainThreadExecutor-to-BukkitScheduler.patch delete mode 100644 patches/server/0480-Allow-adding-items-to-BlockDropItemEvent.patch delete mode 100644 patches/server/0481-Add-getMainThreadExecutor-to-BukkitScheduler.patch create mode 100644 patches/server/0481-living-entity-allow-attribute-registration.patch create mode 100644 patches/server/0482-fix-dead-slime-setSize-invincibility.patch delete mode 100644 patches/server/0482-living-entity-allow-attribute-registration.patch create mode 100644 patches/server/0483-Merchant-getRecipes-should-return-an-immutable-list.patch delete mode 100644 patches/server/0483-fix-dead-slime-setSize-invincibility.patch create mode 100644 patches/server/0484-Expose-Tracked-Players.patch delete mode 100644 patches/server/0484-Merchant-getRecipes-should-return-an-immutable-list.patch delete mode 100644 patches/server/0485-Expose-Tracked-Players.patch create mode 100644 patches/server/0485-Improve-ServerGUI.patch delete mode 100644 patches/server/0486-Improve-ServerGUI.patch create mode 100644 patches/server/0486-fix-converting-txt-to-json-file.patch create mode 100644 patches/server/0487-Add-worldborder-events.patch delete mode 100644 patches/server/0487-fix-converting-txt-to-json-file.patch create mode 100644 patches/server/0488-Add-PlayerNameEntityEvent.patch delete mode 100644 patches/server/0488-Add-worldborder-events.patch delete mode 100644 patches/server/0489-Add-PlayerNameEntityEvent.patch create mode 100644 patches/server/0489-Add-recipe-to-cook-events.patch create mode 100644 patches/server/0490-Add-Block-isValidTool.patch delete mode 100644 patches/server/0490-Add-recipe-to-cook-events.patch delete mode 100644 patches/server/0491-Add-Block-isValidTool.patch create mode 100644 patches/server/0491-Allow-using-signs-inside-spawn-protection.patch delete mode 100644 patches/server/0492-Allow-using-signs-inside-spawn-protection.patch create mode 100644 patches/server/0492-Expand-world-key-API.patch create mode 100644 patches/server/0493-Add-fast-alternative-constructor-for-Rotations.patch delete mode 100644 patches/server/0493-Expand-world-key-API.patch delete mode 100644 patches/server/0494-Add-fast-alternative-constructor-for-Rotations.patch create mode 100644 patches/server/0494-Drop-carried-item-when-player-has-disconnected.patch delete mode 100644 patches/server/0495-Drop-carried-item-when-player-has-disconnected.patch create mode 100644 patches/server/0495-forced-whitelist-use-configurable-kick-message.patch create mode 100644 patches/server/0496-Don-t-ignore-result-of-PlayerEditBookEvent.patch delete mode 100644 patches/server/0496-forced-whitelist-use-configurable-kick-message.patch delete mode 100644 patches/server/0497-Don-t-ignore-result-of-PlayerEditBookEvent.patch create mode 100644 patches/server/0497-Expose-protocol-version.patch create mode 100644 patches/server/0498-Enhance-console-tab-completions-for-brigadier-comman.patch delete mode 100644 patches/server/0498-Expose-protocol-version.patch delete mode 100644 patches/server/0499-Enhance-console-tab-completions-for-brigadier-comman.patch create mode 100644 patches/server/0499-Fix-PlayerItemConsumeEvent-cancelling-properly.patch create mode 100644 patches/server/0500-Add-bypass-host-check.patch delete mode 100644 patches/server/0500-Fix-PlayerItemConsumeEvent-cancelling-properly.patch delete mode 100644 patches/server/0501-Add-bypass-host-check.patch create mode 100644 patches/server/0501-Set-area-affect-cloud-rotation.patch delete mode 100644 patches/server/0502-Set-area-affect-cloud-rotation.patch create mode 100644 patches/server/0502-add-isDeeplySleeping-to-HumanEntity.patch create mode 100644 patches/server/0503-add-consumeFuel-to-FurnaceBurnEvent.patch delete mode 100644 patches/server/0503-add-isDeeplySleeping-to-HumanEntity.patch delete mode 100644 patches/server/0504-add-consumeFuel-to-FurnaceBurnEvent.patch create mode 100644 patches/server/0504-add-get-set-drop-chance-to-EntityEquipment.patch delete mode 100644 patches/server/0505-add-get-set-drop-chance-to-EntityEquipment.patch create mode 100644 patches/server/0505-fix-PigZombieAngerEvent-cancellation.patch delete mode 100644 patches/server/0506-fix-PigZombieAngerEvent-cancellation.patch create mode 100644 patches/server/0506-fix-PlayerItemHeldEvent-firing-twice.patch create mode 100644 patches/server/0507-Add-PlayerDeepSleepEvent.patch delete mode 100644 patches/server/0507-fix-PlayerItemHeldEvent-firing-twice.patch delete mode 100644 patches/server/0508-Add-PlayerDeepSleepEvent.patch create mode 100644 patches/server/0508-More-World-API.patch create mode 100644 patches/server/0509-Add-PlayerBedFailEnterEvent.patch delete mode 100644 patches/server/0509-More-World-API.patch delete mode 100644 patches/server/0510-Add-PlayerBedFailEnterEvent.patch create mode 100644 patches/server/0510-Implement-methods-to-convert-between-Component-and-B.patch create mode 100644 patches/server/0511-Expand-PlayerRespawnEvent-fix-passed-parameter-issue.patch delete mode 100644 patches/server/0511-Implement-methods-to-convert-between-Component-and-B.patch delete mode 100644 patches/server/0512-Expand-PlayerRespawnEvent-fix-passed-parameter-issue.patch create mode 100644 patches/server/0512-Introduce-beacon-activation-deactivation-events.patch create mode 100644 patches/server/0513-Add-Channel-initialization-listeners.patch delete mode 100644 patches/server/0513-Introduce-beacon-activation-deactivation-events.patch delete mode 100644 patches/server/0514-Add-Channel-initialization-listeners.patch create mode 100644 patches/server/0514-Send-empty-commands-if-tab-completion-is-disabled.patch create mode 100644 patches/server/0515-Add-more-WanderingTrader-API.patch delete mode 100644 patches/server/0515-Send-empty-commands-if-tab-completion-is-disabled.patch create mode 100644 patches/server/0516-Add-EntityBlockStorage-clearEntities.patch delete mode 100644 patches/server/0516-Add-more-WanderingTrader-API.patch create mode 100644 patches/server/0517-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch delete mode 100644 patches/server/0517-Add-EntityBlockStorage-clearEntities.patch delete mode 100644 patches/server/0518-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch create mode 100644 patches/server/0518-Add-HiddenPotionEffect-API.patch delete mode 100644 patches/server/0519-Add-HiddenPotionEffect-API.patch create mode 100644 patches/server/0519-Inventory-close.patch create mode 100644 patches/server/0520-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch delete mode 100644 patches/server/0520-Inventory-close.patch delete mode 100644 patches/server/0521-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch create mode 100644 patches/server/0521-Add-basic-Datapack-API.patch delete mode 100644 patches/server/0522-Add-basic-Datapack-API.patch create mode 100644 patches/server/0522-Add-environment-variable-to-disable-server-gui.patch delete mode 100644 patches/server/0523-Add-environment-variable-to-disable-server-gui.patch create mode 100644 patches/server/0523-Expand-PlayerGameModeChangeEvent.patch delete mode 100644 patches/server/0524-Expand-PlayerGameModeChangeEvent.patch create mode 100644 patches/server/0524-ItemStack-repair-check-API.patch delete mode 100644 patches/server/0525-ItemStack-repair-check-API.patch create mode 100644 patches/server/0525-More-Enchantment-API.patch delete mode 100644 patches/server/0526-More-Enchantment-API.patch create mode 100644 patches/server/0526-Move-range-check-for-block-placing-up.patch create mode 100644 patches/server/0527-Add-Mob-lookAt-API.patch delete mode 100644 patches/server/0527-Move-range-check-for-block-placing-up.patch delete mode 100644 patches/server/0528-Add-Mob-lookAt-API.patch create mode 100644 patches/server/0528-Correctly-check-if-bucket-dispenses-will-succeed-for.patch create mode 100644 patches/server/0529-Add-Unix-domain-socket-support.patch delete mode 100644 patches/server/0529-Correctly-check-if-bucket-dispenses-will-succeed-for.patch create mode 100644 patches/server/0530-Add-EntityInsideBlockEvent.patch delete mode 100644 patches/server/0530-Add-Unix-domain-socket-support.patch delete mode 100644 patches/server/0531-Add-EntityInsideBlockEvent.patch create mode 100644 patches/server/0531-Improve-item-default-attribute-API.patch create mode 100644 patches/server/0532-Add-cause-to-Weather-ThunderChangeEvents.patch delete mode 100644 patches/server/0532-Improve-item-default-attribute-API.patch delete mode 100644 patches/server/0533-Add-cause-to-Weather-ThunderChangeEvents.patch create mode 100644 patches/server/0533-More-Lidded-Block-API.patch create mode 100644 patches/server/0534-Limit-item-frame-cursors-on-maps.patch delete mode 100644 patches/server/0534-More-Lidded-Block-API.patch create mode 100644 patches/server/0535-Add-PlayerKickEvent-causes.patch delete mode 100644 patches/server/0535-Limit-item-frame-cursors-on-maps.patch delete mode 100644 patches/server/0536-Add-PlayerKickEvent-causes.patch create mode 100644 patches/server/0536-Add-PufferFishStateChangeEvent.patch delete mode 100644 patches/server/0537-Add-PufferFishStateChangeEvent.patch create mode 100644 patches/server/0537-Fix-PlayerBucketEmptyEvent-result-itemstack.patch delete mode 100644 patches/server/0538-Fix-PlayerBucketEmptyEvent-result-itemstack.patch create mode 100644 patches/server/0538-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch create mode 100644 patches/server/0539-Add-option-to-fix-items-merging-through-walls.patch delete mode 100644 patches/server/0539-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch create mode 100644 patches/server/0540-Add-BellRevealRaiderEvent.patch delete mode 100644 patches/server/0540-Add-option-to-fix-items-merging-through-walls.patch delete mode 100644 patches/server/0541-Add-BellRevealRaiderEvent.patch create mode 100644 patches/server/0541-Fix-invulnerable-end-crystals.patch create mode 100644 patches/server/0542-Add-ElderGuardianAppearanceEvent.patch delete mode 100644 patches/server/0542-Fix-invulnerable-end-crystals.patch delete mode 100644 patches/server/0543-Add-ElderGuardianAppearanceEvent.patch create mode 100644 patches/server/0543-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch create mode 100644 patches/server/0544-Line-Of-Sight-Changes.patch delete mode 100644 patches/server/0544-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch delete mode 100644 patches/server/0545-Line-Of-Sight-Changes.patch create mode 100644 patches/server/0545-add-per-world-spawn-limits.patch create mode 100644 patches/server/0546-Fix-potions-splash-events.patch delete mode 100644 patches/server/0546-add-per-world-spawn-limits.patch create mode 100644 patches/server/0547-Add-more-LimitedRegion-API.patch delete mode 100644 patches/server/0547-Fix-potions-splash-events.patch delete mode 100644 patches/server/0548-Add-more-LimitedRegion-API.patch create mode 100644 patches/server/0548-Fix-PlayerDropItemEvent-using-wrong-item.patch delete mode 100644 patches/server/0549-Fix-PlayerDropItemEvent-using-wrong-item.patch create mode 100644 patches/server/0549-Missing-Entity-API.patch create mode 100644 patches/server/0550-Fix-return-value-of-Block-applyBoneMeal-always-being.patch delete mode 100644 patches/server/0550-Missing-Entity-API.patch delete mode 100644 patches/server/0551-Fix-return-value-of-Block-applyBoneMeal-always-being.patch create mode 100644 patches/server/0551-Use-getChunkIfLoadedImmediately-in-places.patch create mode 100644 patches/server/0552-Fix-commands-from-signs-not-firing-command-events.patch delete mode 100644 patches/server/0552-Use-getChunkIfLoadedImmediately-in-places.patch create mode 100644 patches/server/0553-Add-PlayerArmSwingEvent.patch delete mode 100644 patches/server/0553-Fix-commands-from-signs-not-firing-command-events.patch delete mode 100644 patches/server/0554-Add-PlayerArmSwingEvent.patch create mode 100644 patches/server/0554-Fix-kick-event-leave-message-not-being-sent.patch create mode 100644 patches/server/0555-Don-t-apply-cramming-damage-to-players.patch delete mode 100644 patches/server/0555-Fix-kick-event-leave-message-not-being-sent.patch delete mode 100644 patches/server/0556-Don-t-apply-cramming-damage-to-players.patch create mode 100644 patches/server/0556-Rate-options-and-timings-for-sensors-and-behaviors.patch create mode 100644 patches/server/0557-Add-missing-forceDrop-toggles.patch delete mode 100644 patches/server/0557-Rate-options-and-timings-for-sensors-and-behaviors.patch delete mode 100644 patches/server/0558-Add-missing-forceDrop-toggles.patch create mode 100644 patches/server/0558-Stinger-API.patch create mode 100644 patches/server/0559-Add-System.out-err-catcher.patch delete mode 100644 patches/server/0559-Stinger-API.patch delete mode 100644 patches/server/0560-Add-System.out-err-catcher.patch create mode 100644 patches/server/0560-Prevent-AFK-kick-while-watching-end-credits.patch create mode 100644 patches/server/0561-Allow-skipping-writing-of-comments-to-server.propert.patch delete mode 100644 patches/server/0561-Prevent-AFK-kick-while-watching-end-credits.patch create mode 100644 patches/server/0562-Add-PlayerSetSpawnEvent.patch delete mode 100644 patches/server/0562-Allow-skipping-writing-of-comments-to-server.propert.patch delete mode 100644 patches/server/0563-Add-PlayerSetSpawnEvent.patch create mode 100644 patches/server/0563-Make-hoppers-respect-inventory-max-stack-size.patch delete mode 100644 patches/server/0564-Make-hoppers-respect-inventory-max-stack-size.patch create mode 100644 patches/server/0564-Optimize-entity-tracker-passenger-checks.patch create mode 100644 patches/server/0565-Config-option-for-Piglins-guarding-chests.patch delete mode 100644 patches/server/0565-Optimize-entity-tracker-passenger-checks.patch create mode 100644 patches/server/0566-Add-EntityDamageItemEvent.patch delete mode 100644 patches/server/0566-Config-option-for-Piglins-guarding-chests.patch delete mode 100644 patches/server/0567-Add-EntityDamageItemEvent.patch create mode 100644 patches/server/0567-Optimize-indirect-passenger-iteration.patch create mode 100644 patches/server/0568-Configurable-item-frame-map-cursor-update-interval.patch delete mode 100644 patches/server/0568-Optimize-indirect-passenger-iteration.patch create mode 100644 patches/server/0569-Change-EnderEye-target-without-changing-other-things.patch delete mode 100644 patches/server/0569-Configurable-item-frame-map-cursor-update-interval.patch create mode 100644 patches/server/0570-Add-BlockBreakBlockEvent.patch delete mode 100644 patches/server/0570-Change-EnderEye-target-without-changing-other-things.patch delete mode 100644 patches/server/0571-Add-BlockBreakBlockEvent.patch create mode 100644 patches/server/0571-Option-to-prevent-data-components-copy-in-smithing-r.patch create mode 100644 patches/server/0572-More-CommandBlock-API.patch delete mode 100644 patches/server/0572-Option-to-prevent-data-components-copy-in-smithing-r.patch create mode 100644 patches/server/0573-Add-missing-team-sidebar-display-slots.patch delete mode 100644 patches/server/0573-More-CommandBlock-API.patch create mode 100644 patches/server/0574-Add-back-EntityPortalExitEvent.patch delete mode 100644 patches/server/0574-Add-missing-team-sidebar-display-slots.patch delete mode 100644 patches/server/0575-Add-back-EntityPortalExitEvent.patch create mode 100644 patches/server/0575-Add-methods-to-find-targets-for-lightning-strikes.patch delete mode 100644 patches/server/0576-Add-methods-to-find-targets-for-lightning-strikes.patch create mode 100644 patches/server/0576-Get-entity-default-attributes.patch delete mode 100644 patches/server/0577-Get-entity-default-attributes.patch create mode 100644 patches/server/0577-Left-handed-API.patch create mode 100644 patches/server/0578-Add-more-advancement-API.patch delete mode 100644 patches/server/0578-Left-handed-API.patch create mode 100644 patches/server/0579-Add-ItemFactory-getSpawnEgg-API.patch delete mode 100644 patches/server/0579-Add-more-advancement-API.patch delete mode 100644 patches/server/0580-Add-ItemFactory-getSpawnEgg-API.patch create mode 100644 patches/server/0580-Add-critical-damage-API.patch delete mode 100644 patches/server/0581-Add-critical-damage-API.patch create mode 100644 patches/server/0581-Fix-issues-with-mob-conversion.patch create mode 100644 patches/server/0582-Add-hasCollision-methods-to-various-places.patch delete mode 100644 patches/server/0582-Fix-issues-with-mob-conversion.patch delete mode 100644 patches/server/0583-Add-hasCollision-methods-to-various-places.patch create mode 100644 patches/server/0583-Goat-ram-API.patch create mode 100644 patches/server/0584-Add-API-for-resetting-a-single-score.patch delete mode 100644 patches/server/0584-Goat-ram-API.patch delete mode 100644 patches/server/0585-Add-API-for-resetting-a-single-score.patch create mode 100644 patches/server/0585-Add-Raw-Byte-Entity-Serialization.patch delete mode 100644 patches/server/0586-Add-Raw-Byte-Entity-Serialization.patch create mode 100644 patches/server/0586-Vanilla-command-permission-fixes.patch create mode 100644 patches/server/0587-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch delete mode 100644 patches/server/0587-Vanilla-command-permission-fixes.patch delete mode 100644 patches/server/0588-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch create mode 100644 patches/server/0588-Fix-GameProfileCache-concurrency.patch delete mode 100644 patches/server/0589-Fix-GameProfileCache-concurrency.patch create mode 100644 patches/server/0589-Improve-and-expand-AsyncCatcher.patch create mode 100644 patches/server/0590-Add-paper-mobcaps-and-paper-playermobcaps.patch delete mode 100644 patches/server/0590-Improve-and-expand-AsyncCatcher.patch delete mode 100644 patches/server/0591-Add-paper-mobcaps-and-paper-playermobcaps.patch create mode 100644 patches/server/0591-Sanitize-ResourceLocation-error-logging.patch create mode 100644 patches/server/0592-Manually-inline-methods-in-BlockPosition.patch delete mode 100644 patches/server/0592-Sanitize-ResourceLocation-error-logging.patch delete mode 100644 patches/server/0593-Manually-inline-methods-in-BlockPosition.patch create mode 100644 patches/server/0593-Name-craft-scheduler-threads-according-to-the-plugin.patch create mode 100644 patches/server/0594-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch delete mode 100644 patches/server/0594-Name-craft-scheduler-threads-according-to-the-plugin.patch create mode 100644 patches/server/0595-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch delete mode 100644 patches/server/0595-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch create mode 100644 patches/server/0596-Don-t-lookup-fluid-state-when-raytracing-skip-air-bl.patch delete mode 100644 patches/server/0596-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch delete mode 100644 patches/server/0597-Don-t-lookup-fluid-state-when-raytracing-skip-air-bl.patch create mode 100644 patches/server/0597-Oprimise-map-impl-for-tracked-players.patch create mode 100644 patches/server/0598-Add-missing-InventoryType.patch delete mode 100644 patches/server/0598-Oprimise-map-impl-for-tracked-players.patch delete mode 100644 patches/server/0599-Add-missing-InventoryType.patch create mode 100644 patches/server/0599-Optimise-BlockSoil-nearby-water-lookup.patch create mode 100644 patches/server/0600-Fix-merchant-inventory-not-closing-on-entity-removal.patch delete mode 100644 patches/server/0600-Optimise-BlockSoil-nearby-water-lookup.patch create mode 100644 patches/server/0601-Check-requirement-before-suggesting-root-nodes.patch delete mode 100644 patches/server/0601-Fix-merchant-inventory-not-closing-on-entity-removal.patch delete mode 100644 patches/server/0602-Check-requirement-before-suggesting-root-nodes.patch create mode 100644 patches/server/0602-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch create mode 100644 patches/server/0603-Add-packet-limiter-config.patch delete mode 100644 patches/server/0603-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch delete mode 100644 patches/server/0604-Add-packet-limiter-config.patch create mode 100644 patches/server/0604-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch create mode 100644 patches/server/0605-Ensure-valid-vehicle-status.patch delete mode 100644 patches/server/0605-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch delete mode 100644 patches/server/0606-Ensure-valid-vehicle-status.patch create mode 100644 patches/server/0606-Prevent-softlocked-end-exit-portal-generation.patch create mode 100644 patches/server/0607-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch delete mode 100644 patches/server/0607-Prevent-softlocked-end-exit-portal-generation.patch create mode 100644 patches/server/0608-Don-t-log-debug-logging-being-disabled.patch delete mode 100644 patches/server/0608-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch delete mode 100644 patches/server/0609-Don-t-log-debug-logging-being-disabled.patch create mode 100644 patches/server/0609-fix-various-menus-with-empty-level-accesses.patch create mode 100644 patches/server/0610-Preserve-overstacked-loot.patch delete mode 100644 patches/server/0610-fix-various-menus-with-empty-level-accesses.patch delete mode 100644 patches/server/0611-Preserve-overstacked-loot.patch create mode 100644 patches/server/0611-Update-head-rotation-in-missing-places.patch delete mode 100644 patches/server/0612-Update-head-rotation-in-missing-places.patch create mode 100644 patches/server/0612-prevent-unintended-light-block-manipulation.patch create mode 100644 patches/server/0613-Fix-CraftCriteria-defaults-map.patch delete mode 100644 patches/server/0613-prevent-unintended-light-block-manipulation.patch delete mode 100644 patches/server/0614-Fix-CraftCriteria-defaults-map.patch create mode 100644 patches/server/0614-Fix-upstreams-block-state-factories.patch create mode 100644 patches/server/0615-Configurable-feature-seeds.patch delete mode 100644 patches/server/0615-Fix-upstreams-block-state-factories.patch create mode 100644 patches/server/0616-Add-root-admin-user-detection.patch delete mode 100644 patches/server/0616-Configurable-feature-seeds.patch delete mode 100644 patches/server/0617-Add-root-admin-user-detection.patch create mode 100644 patches/server/0617-don-t-attempt-to-teleport-dead-entities.patch create mode 100644 patches/server/0618-Prevent-excessive-velocity-through-repeated-crits.patch delete mode 100644 patches/server/0618-don-t-attempt-to-teleport-dead-entities.patch delete mode 100644 patches/server/0619-Prevent-excessive-velocity-through-repeated-crits.patch create mode 100644 patches/server/0619-Remove-client-side-code-using-deprecated-for-removal.patch create mode 100644 patches/server/0620-Fix-Spigot-growth-modifiers.patch delete mode 100644 patches/server/0620-Remove-client-side-code-using-deprecated-for-removal.patch delete mode 100644 patches/server/0621-Fix-Spigot-growth-modifiers.patch create mode 100644 patches/server/0621-Prevent-ContainerOpenersCounter-openCount-from-going.patch create mode 100644 patches/server/0622-Add-PlayerItemFrameChangeEvent.patch delete mode 100644 patches/server/0622-Prevent-ContainerOpenersCounter-openCount-from-going.patch delete mode 100644 patches/server/0623-Add-PlayerItemFrameChangeEvent.patch create mode 100644 patches/server/0623-Optimize-HashMapPalette.patch create mode 100644 patches/server/0624-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch delete mode 100644 patches/server/0624-Optimize-HashMapPalette.patch create mode 100644 patches/server/0625-Add-more-Campfire-API.patch delete mode 100644 patches/server/0625-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch delete mode 100644 patches/server/0626-Add-more-Campfire-API.patch create mode 100644 patches/server/0626-Forward-CraftEntity-in-teleport-command.patch delete mode 100644 patches/server/0627-Forward-CraftEntity-in-teleport-command.patch create mode 100644 patches/server/0627-Improve-scoreboard-entries.patch create mode 100644 patches/server/0628-Entity-powdered-snow-API.patch delete mode 100644 patches/server/0628-Improve-scoreboard-entries.patch create mode 100644 patches/server/0629-Add-API-for-item-entity-health.patch delete mode 100644 patches/server/0629-Entity-powdered-snow-API.patch delete mode 100644 patches/server/0630-Add-API-for-item-entity-health.patch create mode 100644 patches/server/0630-Configurable-max-block-light-for-monster-spawning.patch delete mode 100644 patches/server/0631-Configurable-max-block-light-for-monster-spawning.patch create mode 100644 patches/server/0631-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch create mode 100644 patches/server/0632-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch delete mode 100644 patches/server/0632-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch create mode 100644 patches/server/0633-Bucketable-API.patch delete mode 100644 patches/server/0633-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch delete mode 100644 patches/server/0634-Bucketable-API.patch create mode 100644 patches/server/0634-Validate-usernames.patch create mode 100644 patches/server/0635-Make-water-animal-spawn-height-configurable.patch delete mode 100644 patches/server/0635-Validate-usernames.patch create mode 100644 patches/server/0636-Expose-vanilla-BiomeProvider-from-WorldInfo.patch delete mode 100644 patches/server/0636-Make-water-animal-spawn-height-configurable.patch create mode 100644 patches/server/0637-Add-config-option-for-worlds-affected-by-time-cmd.patch delete mode 100644 patches/server/0637-Expose-vanilla-BiomeProvider-from-WorldInfo.patch delete mode 100644 patches/server/0638-Add-config-option-for-worlds-affected-by-time-cmd.patch create mode 100644 patches/server/0638-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch delete mode 100644 patches/server/0639-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch create mode 100644 patches/server/0639-Multiple-Entries-with-Scoreboards.patch delete mode 100644 patches/server/0640-Multiple-Entries-with-Scoreboards.patch create mode 100644 patches/server/0640-Reset-placed-block-on-exception.patch create mode 100644 patches/server/0641-Add-configurable-height-for-slime-spawn.patch delete mode 100644 patches/server/0641-Reset-placed-block-on-exception.patch delete mode 100644 patches/server/0642-Add-configurable-height-for-slime-spawn.patch create mode 100644 patches/server/0642-Fix-xp-reward-for-baby-zombies.patch delete mode 100644 patches/server/0643-Fix-xp-reward-for-baby-zombies.patch create mode 100644 patches/server/0643-Multi-Block-Change-API-Implementation.patch create mode 100644 patches/server/0644-Fix-NotePlayEvent.patch delete mode 100644 patches/server/0644-Multi-Block-Change-API-Implementation.patch delete mode 100644 patches/server/0645-Fix-NotePlayEvent.patch create mode 100644 patches/server/0645-Freeze-Tick-Lock-API.patch delete mode 100644 patches/server/0646-Freeze-Tick-Lock-API.patch create mode 100644 patches/server/0646-More-PotionEffectType-API.patch delete mode 100644 patches/server/0647-More-PotionEffectType-API.patch create mode 100644 patches/server/0647-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch create mode 100644 patches/server/0648-API-for-creating-command-sender-which-forwards-feedb.patch delete mode 100644 patches/server/0648-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch delete mode 100644 patches/server/0649-API-for-creating-command-sender-which-forwards-feedb.patch create mode 100644 patches/server/0649-Add-missing-structure-set-seed-configs.patch delete mode 100644 patches/server/0650-Add-missing-structure-set-seed-configs.patch create mode 100644 patches/server/0650-Fix-cancelled-powdered-snow-bucket-placement.patch create mode 100644 patches/server/0651-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch delete mode 100644 patches/server/0651-Fix-cancelled-powdered-snow-bucket-placement.patch create mode 100644 patches/server/0652-Add-GameEvent-tags.patch delete mode 100644 patches/server/0652-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch delete mode 100644 patches/server/0653-Add-GameEvent-tags.patch create mode 100644 patches/server/0653-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch delete mode 100644 patches/server/0654-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch create mode 100644 patches/server/0654-Furnace-RecipesUsed-API.patch create mode 100644 patches/server/0655-Configurable-sculk-sensor-listener-range.patch delete mode 100644 patches/server/0655-Furnace-RecipesUsed-API.patch create mode 100644 patches/server/0656-Add-missing-block-data-API.patch delete mode 100644 patches/server/0656-Configurable-sculk-sensor-listener-range.patch delete mode 100644 patches/server/0657-Add-missing-block-data-API.patch create mode 100644 patches/server/0657-Option-to-have-default-CustomSpawners-in-custom-worl.patch delete mode 100644 patches/server/0658-Option-to-have-default-CustomSpawners-in-custom-worl.patch create mode 100644 patches/server/0658-Put-world-into-worldlist-before-initing-the-world.patch create mode 100644 patches/server/0659-Custom-Potion-Mixes.patch delete mode 100644 patches/server/0659-Put-world-into-worldlist-before-initing-the-world.patch delete mode 100644 patches/server/0660-Custom-Potion-Mixes.patch create mode 100644 patches/server/0660-Force-close-world-loading-screen.patch create mode 100644 patches/server/0661-Fix-falling-block-spawn-methods.patch delete mode 100644 patches/server/0661-Force-close-world-loading-screen.patch create mode 100644 patches/server/0662-Expose-furnace-minecart-push-values.patch delete mode 100644 patches/server/0662-Fix-falling-block-spawn-methods.patch delete mode 100644 patches/server/0663-Expose-furnace-minecart-push-values.patch create mode 100644 patches/server/0663-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch delete mode 100644 patches/server/0664-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch create mode 100644 patches/server/0664-More-Projectile-API.patch create mode 100644 patches/server/0665-Fix-swamp-hut-cat-generation-deadlock.patch delete mode 100644 patches/server/0665-More-Projectile-API.patch create mode 100644 patches/server/0666-Don-t-allow-vehicle-movement-from-players-while-tele.patch delete mode 100644 patches/server/0666-Fix-swamp-hut-cat-generation-deadlock.patch delete mode 100644 patches/server/0667-Don-t-allow-vehicle-movement-from-players-while-tele.patch create mode 100644 patches/server/0667-Implement-getComputedBiome-API.patch delete mode 100644 patches/server/0668-Implement-getComputedBiome-API.patch create mode 100644 patches/server/0668-Make-some-itemstacks-nonnull.patch create mode 100644 patches/server/0669-Implement-enchantWithLevels-API.patch delete mode 100644 patches/server/0669-Make-some-itemstacks-nonnull.patch create mode 100644 patches/server/0670-Fix-saving-in-unloadWorld.patch delete mode 100644 patches/server/0670-Implement-enchantWithLevels-API.patch create mode 100644 patches/server/0671-Buffer-OOB-setBlock-calls.patch delete mode 100644 patches/server/0671-Fix-saving-in-unloadWorld.patch create mode 100644 patches/server/0672-Add-TameableDeathMessageEvent.patch delete mode 100644 patches/server/0672-Buffer-OOB-setBlock-calls.patch delete mode 100644 patches/server/0673-Add-TameableDeathMessageEvent.patch create mode 100644 patches/server/0673-Fix-new-block-data-for-EntityChangeBlockEvent.patch delete mode 100644 patches/server/0674-Fix-new-block-data-for-EntityChangeBlockEvent.patch create mode 100644 patches/server/0674-fix-player-loottables-running-when-mob-loot-gamerule.patch create mode 100644 patches/server/0675-Ensure-entity-passenger-world-matches-ridden-entity.patch delete mode 100644 patches/server/0675-fix-player-loottables-running-when-mob-loot-gamerule.patch create mode 100644 patches/server/0676-Cache-resource-keys-and-optimize-reference-Holder-ta.patch delete mode 100644 patches/server/0676-Ensure-entity-passenger-world-matches-ridden-entity.patch create mode 100644 patches/server/0677-Allow-changing-the-EnderDragon-podium.patch delete mode 100644 patches/server/0677-Cache-resource-keys-and-optimize-reference-Holder-ta.patch delete mode 100644 patches/server/0678-Allow-changing-the-EnderDragon-podium.patch create mode 100644 patches/server/0678-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch delete mode 100644 patches/server/0679-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch create mode 100644 patches/server/0679-Use-username-instead-of-display-name-in-PlayerList-g.patch create mode 100644 patches/server/0680-Expand-PlayerItemDamageEvent.patch delete mode 100644 patches/server/0680-Use-username-instead-of-display-name-in-PlayerList-g.patch delete mode 100644 patches/server/0681-Expand-PlayerItemDamageEvent.patch create mode 100644 patches/server/0681-WorldCreator-keepSpawnLoaded.patch create mode 100644 patches/server/0682-Fix-CME-in-CraftPersistentDataTypeRegistry.patch delete mode 100644 patches/server/0682-WorldCreator-keepSpawnLoaded.patch delete mode 100644 patches/server/0683-Fix-CME-in-CraftPersistentDataTypeRegistry.patch create mode 100644 patches/server/0683-Trigger-bee_nest_destroyed-trigger-in-the-correct-pl.patch create mode 100644 patches/server/0684-Add-EntityDyeEvent-and-CollarColorable-interface.patch delete mode 100644 patches/server/0684-Trigger-bee_nest_destroyed-trigger-in-the-correct-pl.patch delete mode 100644 patches/server/0685-Add-EntityDyeEvent-and-CollarColorable-interface.patch create mode 100644 patches/server/0685-Fire-CauldronLevelChange-on-initial-fill.patch delete mode 100644 patches/server/0686-Fire-CauldronLevelChange-on-initial-fill.patch create mode 100644 patches/server/0686-fix-powder-snow-cauldrons-not-turning-to-water.patch create mode 100644 patches/server/0687-Add-PlayerStopUsingItemEvent.patch delete mode 100644 patches/server/0687-fix-powder-snow-cauldrons-not-turning-to-water.patch delete mode 100644 patches/server/0688-Add-PlayerStopUsingItemEvent.patch create mode 100644 patches/server/0688-Don-t-tick-markers.patch delete mode 100644 patches/server/0689-Don-t-tick-markers.patch create mode 100644 patches/server/0689-Expand-FallingBlock-API.patch create mode 100644 patches/server/0690-Add-support-for-Proxy-Protocol.patch delete mode 100644 patches/server/0690-Expand-FallingBlock-API.patch delete mode 100644 patches/server/0691-Add-support-for-Proxy-Protocol.patch create mode 100644 patches/server/0691-Fix-OfflinePlayer-getBedSpawnLocation.patch create mode 100644 patches/server/0692-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch delete mode 100644 patches/server/0692-Fix-OfflinePlayer-getBedSpawnLocation.patch delete mode 100644 patches/server/0693-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch create mode 100644 patches/server/0693-Sanitize-sent-BlockEntity-NBT.patch create mode 100644 patches/server/0694-Disable-component-selector-resolving-in-books-by-def.patch delete mode 100644 patches/server/0694-Sanitize-sent-BlockEntity-NBT.patch delete mode 100644 patches/server/0695-Disable-component-selector-resolving-in-books-by-def.patch create mode 100644 patches/server/0695-Prevent-entity-loading-causing-async-lookups.patch delete mode 100644 patches/server/0696-Prevent-entity-loading-causing-async-lookups.patch create mode 100644 patches/server/0696-Throw-exception-on-world-create-while-being-ticked.patch create mode 100644 patches/server/0697-Dont-resent-entity-on-art-update.patch delete mode 100644 patches/server/0697-Throw-exception-on-world-create-while-being-ticked.patch create mode 100644 patches/server/0698-Add-WardenAngerChangeEvent.patch delete mode 100644 patches/server/0698-Dont-resent-entity-on-art-update.patch delete mode 100644 patches/server/0699-Add-WardenAngerChangeEvent.patch create mode 100644 patches/server/0699-Add-option-for-strict-advancement-dimension-checks.patch create mode 100644 patches/server/0700-Add-missing-important-BlockStateListPopulator-method.patch delete mode 100644 patches/server/0700-Add-option-for-strict-advancement-dimension-checks.patch delete mode 100644 patches/server/0701-Add-missing-important-BlockStateListPopulator-method.patch create mode 100644 patches/server/0701-Nameable-Banner-API.patch create mode 100644 patches/server/0702-Don-t-broadcast-messages-to-command-blocks.patch delete mode 100644 patches/server/0702-Nameable-Banner-API.patch delete mode 100644 patches/server/0703-Don-t-broadcast-messages-to-command-blocks.patch create mode 100644 patches/server/0703-Prevent-empty-items-from-being-added-to-world.patch create mode 100644 patches/server/0704-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch delete mode 100644 patches/server/0704-Prevent-empty-items-from-being-added-to-world.patch create mode 100644 patches/server/0705-Add-Player-getFishHook.patch delete mode 100644 patches/server/0705-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch delete mode 100644 patches/server/0706-Add-Player-getFishHook.patch create mode 100644 patches/server/0706-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch create mode 100644 patches/server/0707-Add-various-missing-EntityDropItemEvent-calls.patch delete mode 100644 patches/server/0707-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch delete mode 100644 patches/server/0708-Add-various-missing-EntityDropItemEvent-calls.patch create mode 100644 patches/server/0708-Fix-Bee-flower-NPE.patch delete mode 100644 patches/server/0709-Fix-Bee-flower-NPE.patch create mode 100644 patches/server/0709-More-Teleport-API.patch create mode 100644 patches/server/0710-Add-EntityPortalReadyEvent.patch delete mode 100644 patches/server/0710-More-Teleport-API.patch delete mode 100644 patches/server/0711-Add-EntityPortalReadyEvent.patch create mode 100644 patches/server/0711-Don-t-use-level-random-in-entity-constructors.patch delete mode 100644 patches/server/0712-Don-t-use-level-random-in-entity-constructors.patch create mode 100644 patches/server/0712-Send-block-entities-after-destroy-prediction.patch delete mode 100644 patches/server/0713-Send-block-entities-after-destroy-prediction.patch create mode 100644 patches/server/0713-Warn-on-plugins-accessing-faraway-chunks.patch create mode 100644 patches/server/0714-Custom-Chat-Completion-Suggestions-API.patch delete mode 100644 patches/server/0714-Warn-on-plugins-accessing-faraway-chunks.patch create mode 100644 patches/server/0715-Add-and-fix-missing-BlockFadeEvents.patch delete mode 100644 patches/server/0715-Custom-Chat-Completion-Suggestions-API.patch delete mode 100644 patches/server/0716-Add-and-fix-missing-BlockFadeEvents.patch create mode 100644 patches/server/0716-Collision-API.patch delete mode 100644 patches/server/0717-Collision-API.patch create mode 100644 patches/server/0717-Fix-suggest-command-message-for-brigadier-syntax-exc.patch create mode 100644 patches/server/0718-Block-Ticking-API.patch delete mode 100644 patches/server/0718-Fix-suggest-command-message-for-brigadier-syntax-exc.patch create mode 100644 patches/server/0719-Add-Velocity-IP-Forwarding-Support.patch delete mode 100644 patches/server/0719-Block-Ticking-API.patch create mode 100644 patches/server/0720-Add-NamespacedKey-biome-methods.patch delete mode 100644 patches/server/0720-Add-Velocity-IP-Forwarding-Support.patch delete mode 100644 patches/server/0721-Add-NamespacedKey-biome-methods.patch create mode 100644 patches/server/0721-Fix-plugin-loggers-on-server-shutdown.patch delete mode 100644 patches/server/0722-Fix-plugin-loggers-on-server-shutdown.patch create mode 100644 patches/server/0722-Stop-large-look-changes-from-crashing-the-server.patch create mode 100644 patches/server/0723-Fire-EntityChangeBlockEvent-in-more-places.patch delete mode 100644 patches/server/0723-Stop-large-look-changes-from-crashing-the-server.patch delete mode 100644 patches/server/0724-Fire-EntityChangeBlockEvent-in-more-places.patch create mode 100644 patches/server/0724-Missing-eating-regain-reason.patch delete mode 100644 patches/server/0725-Missing-eating-regain-reason.patch create mode 100644 patches/server/0725-Missing-effect-cause.patch create mode 100644 patches/server/0726-Added-byte-array-serialization-deserialization-for-P.patch delete mode 100644 patches/server/0726-Missing-effect-cause.patch create mode 100644 patches/server/0727-Add-source-block-to-BlockPhysicsEvent.patch delete mode 100644 patches/server/0727-Added-byte-array-serialization-deserialization-for-P.patch delete mode 100644 patches/server/0728-Add-source-block-to-BlockPhysicsEvent.patch create mode 100644 patches/server/0728-Configurable-chat-thread-limit.patch delete mode 100644 patches/server/0729-Configurable-chat-thread-limit.patch create mode 100644 patches/server/0729-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch delete mode 100644 patches/server/0730-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch create mode 100644 patches/server/0730-fix-Jigsaw-block-kicking-user.patch delete mode 100644 patches/server/0731-fix-Jigsaw-block-kicking-user.patch create mode 100644 patches/server/0731-use-BlockFormEvent-for-mud-converting-into-clay.patch create mode 100644 patches/server/0732-Add-getDrops-to-BlockState.patch delete mode 100644 patches/server/0732-use-BlockFormEvent-for-mud-converting-into-clay.patch delete mode 100644 patches/server/0733-Add-getDrops-to-BlockState.patch create mode 100644 patches/server/0733-Fix-a-bunch-of-vanilla-bugs.patch delete mode 100644 patches/server/0734-Fix-a-bunch-of-vanilla-bugs.patch create mode 100644 patches/server/0734-Remove-unnecessary-onTrackingStart-during-navigation.patch create mode 100644 patches/server/0735-Fix-custom-piglin-loved-items.patch delete mode 100644 patches/server/0735-Remove-unnecessary-onTrackingStart-during-navigation.patch create mode 100644 patches/server/0736-EntityPickupItemEvent-fixes.patch delete mode 100644 patches/server/0736-Fix-custom-piglin-loved-items.patch create mode 100644 patches/server/0737-Correctly-handle-interactions-with-items-on-cooldown.patch delete mode 100644 patches/server/0737-EntityPickupItemEvent-fixes.patch create mode 100644 patches/server/0738-Add-PlayerInventorySlotChangeEvent.patch delete mode 100644 patches/server/0738-Correctly-handle-interactions-with-items-on-cooldown.patch delete mode 100644 patches/server/0739-Add-PlayerInventorySlotChangeEvent.patch create mode 100644 patches/server/0739-Elder-Guardian-appearance-API.patch create mode 100644 patches/server/0740-Add-entity-knockback-API.patch delete mode 100644 patches/server/0740-Elder-Guardian-appearance-API.patch delete mode 100644 patches/server/0741-Add-entity-knockback-API.patch create mode 100644 patches/server/0741-Detect-headless-JREs.patch delete mode 100644 patches/server/0742-Detect-headless-JREs.patch create mode 100644 patches/server/0742-fix-entity-vehicle-collision-event-not-called.patch create mode 100644 patches/server/0743-Add-EntityToggleSitEvent.patch delete mode 100644 patches/server/0743-fix-entity-vehicle-collision-event-not-called.patch delete mode 100644 patches/server/0744-Add-EntityToggleSitEvent.patch create mode 100644 patches/server/0744-Add-fire-tick-delay-option.patch create mode 100644 patches/server/0745-Add-Moving-Piston-API.patch delete mode 100644 patches/server/0745-Add-fire-tick-delay-option.patch delete mode 100644 patches/server/0746-Add-Moving-Piston-API.patch create mode 100644 patches/server/0746-Ignore-impossible-spawn-tick.patch create mode 100644 patches/server/0747-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch delete mode 100644 patches/server/0747-Ignore-impossible-spawn-tick.patch delete mode 100644 patches/server/0748-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch create mode 100644 patches/server/0748-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch create mode 100644 patches/server/0749-Add-PrePlayerAttackEntityEvent.patch delete mode 100644 patches/server/0749-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch delete mode 100644 patches/server/0750-Add-PrePlayerAttackEntityEvent.patch create mode 100644 patches/server/0750-ensure-reset-EnderDragon-boss-event-name.patch create mode 100644 patches/server/0751-Add-Player-Warden-Warning-API.patch delete mode 100644 patches/server/0751-ensure-reset-EnderDragon-boss-event-name.patch delete mode 100644 patches/server/0752-Add-Player-Warden-Warning-API.patch create mode 100644 patches/server/0752-More-vanilla-friendly-methods-to-update-trades.patch create mode 100644 patches/server/0753-Add-paper-dumplisteners-command.patch delete mode 100644 patches/server/0753-More-vanilla-friendly-methods-to-update-trades.patch delete mode 100644 patches/server/0754-Add-paper-dumplisteners-command.patch create mode 100644 patches/server/0754-check-global-player-list-where-appropriate.patch create mode 100644 patches/server/0755-Fix-async-entity-add-due-to-fungus-trees.patch delete mode 100644 patches/server/0755-check-global-player-list-where-appropriate.patch delete mode 100644 patches/server/0756-Fix-async-entity-add-due-to-fungus-trees.patch create mode 100644 patches/server/0756-ItemStack-damage-API.patch create mode 100644 patches/server/0757-Friction-API.patch delete mode 100644 patches/server/0757-ItemStack-damage-API.patch create mode 100644 patches/server/0758-Ability-to-control-player-s-insomnia-and-phantoms.patch delete mode 100644 patches/server/0758-Friction-API.patch delete mode 100644 patches/server/0759-Ability-to-control-player-s-insomnia-and-phantoms.patch create mode 100644 patches/server/0759-Fix-premature-player-kicks-on-shutdown.patch delete mode 100644 patches/server/0760-Fix-premature-player-kicks-on-shutdown.patch create mode 100644 patches/server/0760-Sync-offhand-slot-in-menus.patch create mode 100644 patches/server/0761-Player-Entity-Tracking-Events.patch delete mode 100644 patches/server/0761-Sync-offhand-slot-in-menus.patch create mode 100644 patches/server/0762-Limit-pet-look-distance.patch delete mode 100644 patches/server/0762-Player-Entity-Tracking-Events.patch delete mode 100644 patches/server/0763-Limit-pet-look-distance.patch create mode 100644 patches/server/0763-fix-Instruments.patch create mode 100644 patches/server/0764-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch delete mode 100644 patches/server/0764-fix-Instruments.patch create mode 100644 patches/server/0765-Add-BlockLockCheckEvent.patch delete mode 100644 patches/server/0765-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch delete mode 100644 patches/server/0766-Add-BlockLockCheckEvent.patch create mode 100644 patches/server/0766-Add-Sneaking-API-for-Entities.patch delete mode 100644 patches/server/0767-Add-Sneaking-API-for-Entities.patch create mode 100644 patches/server/0767-Improve-logging-and-errors.patch create mode 100644 patches/server/0768-Improve-PortalEvents.patch delete mode 100644 patches/server/0768-Improve-logging-and-errors.patch create mode 100644 patches/server/0769-Add-config-option-for-spider-worldborder-climbing.patch delete mode 100644 patches/server/0769-Improve-PortalEvents.patch delete mode 100644 patches/server/0770-Add-config-option-for-spider-worldborder-climbing.patch create mode 100644 patches/server/0770-Add-missing-SpigotConfig-logCommands-check.patch delete mode 100644 patches/server/0771-Add-missing-SpigotConfig-logCommands-check.patch create mode 100644 patches/server/0771-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch delete mode 100644 patches/server/0772-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch create mode 100644 patches/server/0772-Flying-Fall-Damage.patch create mode 100644 patches/server/0773-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch delete mode 100644 patches/server/0773-Flying-Fall-Damage.patch delete mode 100644 patches/server/0774-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch create mode 100644 patches/server/0774-config-for-disabling-entity-tag-tags.patch create mode 100644 patches/server/0775-Use-single-player-info-update-packet-on-join.patch delete mode 100644 patches/server/0775-config-for-disabling-entity-tag-tags.patch create mode 100644 patches/server/0776-Correctly-shrink-items-during-EntityResurrectEvent.patch delete mode 100644 patches/server/0776-Use-single-player-info-update-packet-on-join.patch delete mode 100644 patches/server/0777-Correctly-shrink-items-during-EntityResurrectEvent.patch create mode 100644 patches/server/0777-Win-Screen-API.patch create mode 100644 patches/server/0778-Remove-CraftItemStack-setAmount-null-assignment.patch delete mode 100644 patches/server/0778-Win-Screen-API.patch create mode 100644 patches/server/0779-Fix-force-opening-enchantment-tables.patch delete mode 100644 patches/server/0779-Remove-CraftItemStack-setAmount-null-assignment.patch create mode 100644 patches/server/0780-Add-Entity-Body-Yaw-API.patch delete mode 100644 patches/server/0780-Fix-force-opening-enchantment-tables.patch delete mode 100644 patches/server/0781-Add-Entity-Body-Yaw-API.patch create mode 100644 patches/server/0781-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch create mode 100644 patches/server/0782-Add-EntityFertilizeEggEvent.patch delete mode 100644 patches/server/0782-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch delete mode 100644 patches/server/0783-Add-EntityFertilizeEggEvent.patch create mode 100644 patches/server/0783-Fix-HumanEntity-drop-not-updating-the-client-inv.patch create mode 100644 patches/server/0784-Add-CompostItemEvent-and-EntityCompostItemEvent.patch delete mode 100644 patches/server/0784-Fix-HumanEntity-drop-not-updating-the-client-inv.patch delete mode 100644 patches/server/0785-Add-CompostItemEvent-and-EntityCompostItemEvent.patch create mode 100644 patches/server/0785-Correctly-handle-ArmorStand-invisibility.patch delete mode 100644 patches/server/0786-Correctly-handle-ArmorStand-invisibility.patch create mode 100644 patches/server/0786-Fix-advancement-triggers-for-entity-damage.patch delete mode 100644 patches/server/0787-Fix-advancement-triggers-for-entity-damage.patch create mode 100644 patches/server/0787-Fix-text-display-error-on-spawn.patch create mode 100644 patches/server/0788-Fix-inventories-returning-null-Locations.patch delete mode 100644 patches/server/0788-Fix-text-display-error-on-spawn.patch create mode 100644 patches/server/0789-Add-Shearable-API.patch delete mode 100644 patches/server/0789-Fix-inventories-returning-null-Locations.patch delete mode 100644 patches/server/0790-Add-Shearable-API.patch create mode 100644 patches/server/0790-Fix-SpawnEggMeta-get-setSpawnedType.patch delete mode 100644 patches/server/0791-Fix-SpawnEggMeta-get-setSpawnedType.patch create mode 100644 patches/server/0791-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch delete mode 100644 patches/server/0792-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch create mode 100644 patches/server/0792-Treat-sequence-violations-like-they-should-be.patch create mode 100644 patches/server/0793-Prevent-causing-expired-keys-from-impacting-new-join.patch delete mode 100644 patches/server/0793-Treat-sequence-violations-like-they-should-be.patch create mode 100644 patches/server/0794-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch delete mode 100644 patches/server/0794-Prevent-causing-expired-keys-from-impacting-new-join.patch delete mode 100644 patches/server/0795-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch create mode 100644 patches/server/0795-Use-array-for-gamerule-storage.patch create mode 100644 patches/server/0796-Fix-a-couple-of-upstream-bed-issues.patch delete mode 100644 patches/server/0796-Use-array-for-gamerule-storage.patch delete mode 100644 patches/server/0797-Fix-a-couple-of-upstream-bed-issues.patch create mode 100644 patches/server/0797-Fix-demo-flag-not-enabling-demo-mode.patch create mode 100644 patches/server/0798-Add-Mob-Experience-reward-API.patch delete mode 100644 patches/server/0798-Fix-demo-flag-not-enabling-demo-mode.patch delete mode 100644 patches/server/0799-Add-Mob-Experience-reward-API.patch create mode 100644 patches/server/0799-Break-redstone-on-top-of-trap-doors-early.patch create mode 100644 patches/server/0800-Avoid-Lazy-Initialization-for-Enum-Fields.patch delete mode 100644 patches/server/0800-Break-redstone-on-top-of-trap-doors-early.patch delete mode 100644 patches/server/0801-Avoid-Lazy-Initialization-for-Enum-Fields.patch create mode 100644 patches/server/0801-More-accurate-isInOpenWater-impl.patch create mode 100644 patches/server/0802-Expand-PlayerItemMendEvent.patch delete mode 100644 patches/server/0802-More-accurate-isInOpenWater-impl.patch delete mode 100644 patches/server/0803-Expand-PlayerItemMendEvent.patch create mode 100644 patches/server/0803-Refresh-ProjectileSource-for-projectiles.patch create mode 100644 patches/server/0804-Add-transient-modifier-API.patch delete mode 100644 patches/server/0804-Refresh-ProjectileSource-for-projectiles.patch delete mode 100644 patches/server/0805-Add-transient-modifier-API.patch create mode 100644 patches/server/0805-Fix-block-place-logic.patch delete mode 100644 patches/server/0806-Fix-block-place-logic.patch create mode 100644 patches/server/0806-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch create mode 100644 patches/server/0807-Call-BlockGrowEvent-for-missing-blocks.patch delete mode 100644 patches/server/0807-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch delete mode 100644 patches/server/0808-Call-BlockGrowEvent-for-missing-blocks.patch create mode 100644 patches/server/0808-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch delete mode 100644 patches/server/0809-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch create mode 100644 patches/server/0809-fix-MapLike-spam-for-missing-key-selector.patch create mode 100644 patches/server/0810-Fix-sniffer-removeExploredLocation.patch delete mode 100644 patches/server/0810-fix-MapLike-spam-for-missing-key-selector.patch create mode 100644 patches/server/0811-Add-method-to-remove-all-active-potion-effects.patch delete mode 100644 patches/server/0811-Fix-sniffer-removeExploredLocation.patch create mode 100644 patches/server/0812-Add-event-for-player-editing-sign.patch delete mode 100644 patches/server/0812-Add-method-to-remove-all-active-potion-effects.patch delete mode 100644 patches/server/0813-Add-event-for-player-editing-sign.patch create mode 100644 patches/server/0813-Only-tick-item-frames-if-players-can-see-it.patch create mode 100644 patches/server/0814-Fix-cmd-permission-levels-for-command-blocks.patch delete mode 100644 patches/server/0814-Only-tick-item-frames-if-players-can-see-it.patch create mode 100644 patches/server/0815-Add-option-to-disable-block-updates.patch delete mode 100644 patches/server/0815-Fix-cmd-permission-levels-for-command-blocks.patch delete mode 100644 patches/server/0816-Add-option-to-disable-block-updates.patch create mode 100644 patches/server/0816-Call-missing-BlockDispenseEvent.patch delete mode 100644 patches/server/0817-Call-missing-BlockDispenseEvent.patch create mode 100644 patches/server/0817-Don-t-load-chunks-for-supporting-block-checks.patch delete mode 100644 patches/server/0818-Don-t-load-chunks-for-supporting-block-checks.patch create mode 100644 patches/server/0818-Optimize-player-lookups-for-beacons.patch create mode 100644 patches/server/0819-More-Sign-Block-API.patch delete mode 100644 patches/server/0819-Optimize-player-lookups-for-beacons.patch delete mode 100644 patches/server/0820-More-Sign-Block-API.patch create mode 100644 patches/server/0820-fix-item-meta-for-tadpole-buckets.patch create mode 100644 patches/server/0821-Fix-BanList-API.patch delete mode 100644 patches/server/0821-fix-item-meta-for-tadpole-buckets.patch create mode 100644 patches/server/0822-Determine-lava-and-water-fluid-explosion-resistance-.patch delete mode 100644 patches/server/0822-Fix-BanList-API.patch delete mode 100644 patches/server/0823-Determine-lava-and-water-fluid-explosion-resistance-.patch create mode 100644 patches/server/0823-Fix-possible-NPE-on-painting-creation.patch delete mode 100644 patches/server/0824-Fix-possible-NPE-on-painting-creation.patch create mode 100644 patches/server/0824-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch create mode 100644 patches/server/0825-ExperienceOrb-should-call-EntitySpawnEvent.patch delete mode 100644 patches/server/0825-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch delete mode 100644 patches/server/0826-ExperienceOrb-should-call-EntitySpawnEvent.patch create mode 100644 patches/server/0826-Make-Amethyst-throw-both-Spread-and-Grow-Events.patch create mode 100644 patches/server/0827-Add-whitelist-events.patch delete mode 100644 patches/server/0827-Make-Amethyst-throw-both-Spread-and-Grow-Events.patch delete mode 100644 patches/server/0828-Add-whitelist-events.patch create mode 100644 patches/server/0828-Implement-PlayerFailMoveEvent.patch create mode 100644 patches/server/0829-Folia-scheduler-and-owned-region-API.patch delete mode 100644 patches/server/0829-Implement-PlayerFailMoveEvent.patch delete mode 100644 patches/server/0830-Folia-scheduler-and-owned-region-API.patch create mode 100644 patches/server/0830-Only-erase-allay-memory-on-non-item-targets.patch create mode 100644 patches/server/0831-Fix-rotation-when-spawning-display-entities.patch delete mode 100644 patches/server/0831-Only-erase-allay-memory-on-non-item-targets.patch delete mode 100644 patches/server/0832-Fix-rotation-when-spawning-display-entities.patch create mode 100644 patches/server/0832-Only-capture-actual-tree-growth.patch delete mode 100644 patches/server/0833-Only-capture-actual-tree-growth.patch create mode 100644 patches/server/0833-Use-correct-source-for-mushroom-block-spread-event.patch create mode 100644 patches/server/0834-Respect-randomizeData-on-more-entities-when-spawning.patch delete mode 100644 patches/server/0834-Use-correct-source-for-mushroom-block-spread-event.patch delete mode 100644 patches/server/0835-Respect-randomizeData-on-more-entities-when-spawning.patch create mode 100644 patches/server/0835-Use-correct-seed-on-api-world-load.patch create mode 100644 patches/server/0836-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch delete mode 100644 patches/server/0836-Use-correct-seed-on-api-world-load.patch create mode 100644 patches/server/0837-Cache-map-ids-on-item-frames.patch delete mode 100644 patches/server/0837-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch create mode 100644 patches/server/0838-API-for-updating-recipes-on-clients.patch delete mode 100644 patches/server/0838-Cache-map-ids-on-item-frames.patch delete mode 100644 patches/server/0839-API-for-updating-recipes-on-clients.patch create mode 100644 patches/server/0839-Fix-custom-statistic-criteria-creation.patch create mode 100644 patches/server/0840-Bandaid-fix-for-Effect.patch delete mode 100644 patches/server/0840-Fix-custom-statistic-criteria-creation.patch delete mode 100644 patches/server/0841-Bandaid-fix-for-Effect.patch create mode 100644 patches/server/0841-SculkCatalyst-bloom-API.patch create mode 100644 patches/server/0842-API-for-an-entity-s-scoreboard-name.patch delete mode 100644 patches/server/0842-SculkCatalyst-bloom-API.patch delete mode 100644 patches/server/0843-API-for-an-entity-s-scoreboard-name.patch create mode 100644 patches/server/0843-Deprecate-and-replace-methods-with-old-StructureType.patch delete mode 100644 patches/server/0844-Deprecate-and-replace-methods-with-old-StructureType.patch create mode 100644 patches/server/0844-Don-t-tab-complete-namespaced-commands-if-send-names.patch delete mode 100644 patches/server/0845-Don-t-tab-complete-namespaced-commands-if-send-names.patch create mode 100644 patches/server/0845-Properly-handle-BlockBreakEvent-isDropItems.patch create mode 100644 patches/server/0846-Fire-entity-death-event-for-ender-dragon.patch delete mode 100644 patches/server/0846-Properly-handle-BlockBreakEvent-isDropItems.patch create mode 100644 patches/server/0847-Configurable-entity-tracking-range-by-Y-coordinate.patch delete mode 100644 patches/server/0847-Fire-entity-death-event-for-ender-dragon.patch create mode 100644 patches/server/0848-Add-Listing-API-for-Player.patch delete mode 100644 patches/server/0848-Configurable-entity-tracking-range-by-Y-coordinate.patch delete mode 100644 patches/server/0849-Add-Listing-API-for-Player.patch create mode 100644 patches/server/0849-Configurable-Region-Compression-Format.patch create mode 100644 patches/server/0850-Add-BlockFace-to-BlockDamageEvent.patch delete mode 100644 patches/server/0850-Configurable-Region-Compression-Format.patch delete mode 100644 patches/server/0851-Add-BlockFace-to-BlockDamageEvent.patch create mode 100644 patches/server/0851-Fix-NPE-on-Boat-getStatus.patch create mode 100644 patches/server/0852-Expand-Pose-API.patch delete mode 100644 patches/server/0852-Fix-NPE-on-Boat-getStatus.patch delete mode 100644 patches/server/0853-Expand-Pose-API.patch create mode 100644 patches/server/0853-More-DragonBattle-API.patch create mode 100644 patches/server/0854-Add-PlayerPickItemEvent.patch delete mode 100644 patches/server/0854-More-DragonBattle-API.patch delete mode 100644 patches/server/0855-Add-PlayerPickItemEvent.patch create mode 100644 patches/server/0855-Allow-trident-custom-damage.patch delete mode 100644 patches/server/0856-Allow-trident-custom-damage.patch create mode 100644 patches/server/0856-Expose-hand-in-BlockCanBuildEvent.patch delete mode 100644 patches/server/0857-Expose-hand-in-BlockCanBuildEvent.patch create mode 100644 patches/server/0857-Optimize-nearest-structure-border-iteration.patch create mode 100644 patches/server/0858-Implement-OfflinePlayer-isConnected.patch delete mode 100644 patches/server/0858-Optimize-nearest-structure-border-iteration.patch create mode 100644 patches/server/0859-Fix-slot-desync.patch delete mode 100644 patches/server/0859-Implement-OfflinePlayer-isConnected.patch create mode 100644 patches/server/0860-Add-titleOverride-to-InventoryOpenEvent.patch delete mode 100644 patches/server/0860-Fix-slot-desync.patch delete mode 100644 patches/server/0861-Add-titleOverride-to-InventoryOpenEvent.patch create mode 100644 patches/server/0861-Configure-sniffer-egg-hatch-time.patch delete mode 100644 patches/server/0862-Configure-sniffer-egg-hatch-time.patch create mode 100644 patches/server/0862-Do-crystal-portal-proximity-check-before-entity-look.patch delete mode 100644 patches/server/0863-Do-crystal-portal-proximity-check-before-entity-look.patch create mode 100644 patches/server/0863-Skip-POI-finding-if-stuck-in-vehicle.patch create mode 100644 patches/server/0864-Add-slot-sanity-checks-in-container-clicks.patch delete mode 100644 patches/server/0864-Skip-POI-finding-if-stuck-in-vehicle.patch delete mode 100644 patches/server/0865-Add-slot-sanity-checks-in-container-clicks.patch create mode 100644 patches/server/0865-Call-BlockRedstoneEvents-properly.patch create mode 100644 patches/server/0866-Allow-proper-checking-of-empty-item-stacks.patch delete mode 100644 patches/server/0866-Call-BlockRedstoneEvents-properly.patch delete mode 100644 patches/server/0867-Allow-proper-checking-of-empty-item-stacks.patch create mode 100644 patches/server/0867-Fix-silent-equipment-change-for-mobs.patch delete mode 100644 patches/server/0868-Fix-silent-equipment-change-for-mobs.patch create mode 100644 patches/server/0868-Fix-spigot-s-Forced-Stats.patch create mode 100644 patches/server/0869-Add-missing-InventoryHolders-to-inventories.patch delete mode 100644 patches/server/0869-Fix-spigot-s-Forced-Stats.patch delete mode 100644 patches/server/0870-Add-missing-InventoryHolders-to-inventories.patch create mode 100644 patches/server/0870-Do-not-read-tile-entities-in-chunks-that-are-positio.patch create mode 100644 patches/server/0871-Add-missing-logs-for-log-ips-config-option.patch delete mode 100644 patches/server/0871-Do-not-read-tile-entities-in-chunks-that-are-positio.patch delete mode 100644 patches/server/0872-Add-missing-logs-for-log-ips-config-option.patch create mode 100644 patches/server/0872-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch create mode 100644 patches/server/0873-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch delete mode 100644 patches/server/0873-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch delete mode 100644 patches/server/0874-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch create mode 100644 patches/server/0874-Fix-team-sidebar-objectives-not-being-cleared.patch create mode 100644 patches/server/0875-Fix-missing-map-initialize-event-call.patch delete mode 100644 patches/server/0875-Fix-team-sidebar-objectives-not-being-cleared.patch delete mode 100644 patches/server/0876-Fix-missing-map-initialize-event-call.patch create mode 100644 patches/server/0876-Update-entity-data-when-attaching-firework-to-entity.patch create mode 100644 patches/server/0877-Fix-UnsafeValues-loadAdvancement.patch delete mode 100644 patches/server/0877-Update-entity-data-when-attaching-firework-to-entity.patch create mode 100644 patches/server/0878-Add-player-idle-duration-API.patch delete mode 100644 patches/server/0878-Fix-UnsafeValues-loadAdvancement.patch delete mode 100644 patches/server/0879-Add-player-idle-duration-API.patch create mode 100644 patches/server/0879-Don-t-check-if-we-can-see-non-visible-entities.patch delete mode 100644 patches/server/0880-Don-t-check-if-we-can-see-non-visible-entities.patch create mode 100644 patches/server/0880-Fix-NPE-in-SculkBloomEvent-world-access.patch create mode 100644 patches/server/0881-Allow-null-itemstack-for-Player-sendEquipmentChange.patch delete mode 100644 patches/server/0881-Fix-NPE-in-SculkBloomEvent-world-access.patch delete mode 100644 patches/server/0882-Allow-null-itemstack-for-Player-sendEquipmentChange.patch create mode 100644 patches/server/0882-Optimize-VarInts.patch create mode 100644 patches/server/0883-Add-API-to-get-the-collision-shape-of-a-block-before.patch delete mode 100644 patches/server/0883-Optimize-VarInts.patch delete mode 100644 patches/server/0884-Add-API-to-get-the-collision-shape-of-a-block-before.patch create mode 100644 patches/server/0884-Add-predicate-for-blocks-when-raytracing.patch delete mode 100644 patches/server/0885-Add-predicate-for-blocks-when-raytracing.patch create mode 100644 patches/server/0885-Broadcast-take-item-packets-with-collector-as-source.patch delete mode 100644 patches/server/0886-Broadcast-take-item-packets-with-collector-as-source.patch create mode 100644 patches/server/0886-Expand-LingeringPotion-API.patch delete mode 100644 patches/server/0887-Expand-LingeringPotion-API.patch create mode 100644 patches/server/0887-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch create mode 100644 patches/server/0888-Add-hand-to-fish-event-for-all-player-interactions.patch delete mode 100644 patches/server/0888-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch delete mode 100644 patches/server/0889-Add-hand-to-fish-event-for-all-player-interactions.patch create mode 100644 patches/server/0889-Fix-several-issues-with-EntityBreedEvent.patch create mode 100644 patches/server/0890-Add-UUID-attribute-modifier-API.patch delete mode 100644 patches/server/0890-Fix-several-issues-with-EntityBreedEvent.patch delete mode 100644 patches/server/0891-Add-UUID-attribute-modifier-API.patch create mode 100644 patches/server/0891-Fix-missing-event-call-for-entity-teleport-API.patch delete mode 100644 patches/server/0892-Fix-missing-event-call-for-entity-teleport-API.patch create mode 100644 patches/server/0892-Lazily-create-LootContext-for-criterions.patch create mode 100644 patches/server/0893-Don-t-fire-sync-events-during-worldgen.patch delete mode 100644 patches/server/0893-Lazily-create-LootContext-for-criterions.patch create mode 100644 patches/server/0894-Add-Structure-check-API.patch delete mode 100644 patches/server/0894-Don-t-fire-sync-events-during-worldgen.patch delete mode 100644 patches/server/0895-Add-Structure-check-API.patch create mode 100644 patches/server/0895-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch delete mode 100644 patches/server/0896-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch create mode 100644 patches/server/0896-Restore-vanilla-entity-drops-behavior.patch create mode 100644 patches/server/0897-Dont-resend-blocks-on-interactions.patch delete mode 100644 patches/server/0897-Restore-vanilla-entity-drops-behavior.patch delete mode 100644 patches/server/0898-Dont-resend-blocks-on-interactions.patch create mode 100644 patches/server/0898-add-more-scoreboard-API.patch create mode 100644 patches/server/0899-Improve-Registry.patch delete mode 100644 patches/server/0899-add-more-scoreboard-API.patch create mode 100644 patches/server/0900-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch delete mode 100644 patches/server/0900-Improve-Registry.patch create mode 100644 patches/server/0901-Add-experience-points-API.patch delete mode 100644 patches/server/0901-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch create mode 100644 patches/server/0902-Add-drops-to-shear-events.patch delete mode 100644 patches/server/0902-Add-experience-points-API.patch create mode 100644 patches/server/0903-Add-PlayerShieldDisableEvent.patch delete mode 100644 patches/server/0903-Add-drops-to-shear-events.patch delete mode 100644 patches/server/0904-Add-PlayerShieldDisableEvent.patch create mode 100644 patches/server/0904-Validate-ResourceLocation-in-NBT-reading.patch create mode 100644 patches/server/0905-Properly-handle-experience-dropping-on-block-break.patch delete mode 100644 patches/server/0905-Validate-ResourceLocation-in-NBT-reading.patch create mode 100644 patches/server/0906-Fixup-NamespacedKey-handling.patch delete mode 100644 patches/server/0906-Properly-handle-experience-dropping-on-block-break.patch create mode 100644 patches/server/0907-Expose-LootTable-of-DecoratedPot.patch delete mode 100644 patches/server/0907-Fixup-NamespacedKey-handling.patch delete mode 100644 patches/server/0908-Expose-LootTable-of-DecoratedPot.patch create mode 100644 patches/server/0908-Reduce-allocation-of-Vec3D-by-entity-tracker.patch create mode 100644 patches/server/0909-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch delete mode 100644 patches/server/0909-Reduce-allocation-of-Vec3D-by-entity-tracker.patch delete mode 100644 patches/server/0910-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch create mode 100644 patches/server/0910-Add-ShulkerDuplicateEvent.patch delete mode 100644 patches/server/0911-Add-ShulkerDuplicateEvent.patch create mode 100644 patches/server/0911-Add-api-for-spawn-egg-texture-colors.patch create mode 100644 patches/server/0912-Add-Lifecycle-Event-system.patch delete mode 100644 patches/server/0912-Add-api-for-spawn-egg-texture-colors.patch delete mode 100644 patches/server/0913-Add-Lifecycle-Event-system.patch create mode 100644 patches/server/0913-ItemStack-Tooltip-API.patch create mode 100644 patches/server/0914-Add-getChunkSnapshot-includeLightData-parameter.patch delete mode 100644 patches/server/0914-ItemStack-Tooltip-API.patch create mode 100644 patches/server/0915-Add-FluidState-API.patch delete mode 100644 patches/server/0915-Add-getChunkSnapshot-includeLightData-parameter.patch delete mode 100644 patches/server/0916-Add-FluidState-API.patch create mode 100644 patches/server/0916-add-number-format-api.patch delete mode 100644 patches/server/0917-add-number-format-api.patch create mode 100644 patches/server/0917-improve-BanList-types.patch create mode 100644 patches/server/0918-Expanded-Hopper-API.patch delete mode 100644 patches/server/0918-improve-BanList-types.patch create mode 100644 patches/server/0919-Add-BlockBreakProgressUpdateEvent.patch delete mode 100644 patches/server/0919-Expanded-Hopper-API.patch delete mode 100644 patches/server/0920-Add-BlockBreakProgressUpdateEvent.patch create mode 100644 patches/server/0920-Deprecate-ItemStack-setType.patch create mode 100644 patches/server/0921-Add-CartographyItemEvent.patch delete mode 100644 patches/server/0921-Deprecate-ItemStack-setType.patch delete mode 100644 patches/server/0922-Add-CartographyItemEvent.patch create mode 100644 patches/server/0922-More-Raid-API.patch create mode 100644 patches/server/0923-Add-onboarding-message-for-initial-server-start.patch delete mode 100644 patches/server/0923-More-Raid-API.patch delete mode 100644 patches/server/0924-Add-onboarding-message-for-initial-server-start.patch create mode 100644 patches/server/0924-Configurable-max-block-fluid-ticks.patch delete mode 100644 patches/server/0925-Configurable-max-block-fluid-ticks.patch create mode 100644 patches/server/0925-Fix-bees-aging-inside-hives.patch create mode 100644 patches/server/0926-Disable-memory-reserve-allocating.patch delete mode 100644 patches/server/0926-Fix-bees-aging-inside-hives.patch delete mode 100644 patches/server/0927-Disable-memory-reserve-allocating.patch create mode 100644 patches/server/0927-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch delete mode 100644 patches/server/0928-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch create mode 100644 patches/server/0928-Fix-DamageSource-API.patch delete mode 100644 patches/server/0929-Fix-DamageSource-API.patch create mode 100644 patches/server/0929-Fix-creation-of-invalid-block-entity-during-world-ge.patch delete mode 100644 patches/server/0930-Fix-creation-of-invalid-block-entity-during-world-ge.patch create mode 100644 patches/server/0930-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch delete mode 100644 patches/server/0931-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch create mode 100644 patches/server/0931-Improve-tag-parser-handling.patch delete mode 100644 patches/server/0932-Improve-tag-parser-handling.patch create mode 100644 patches/server/0932-Item-Mutation-Fixes.patch delete mode 100644 patches/server/0933-Item-Mutation-Fixes.patch create mode 100644 patches/server/0933-Per-world-ticks-per-spawn-settings.patch delete mode 100644 patches/server/0934-Per-world-ticks-per-spawn-settings.patch create mode 100644 patches/server/0934-Properly-track-the-changed-item-from-dispense-events.patch delete mode 100644 patches/server/0935-Properly-track-the-changed-item-from-dispense-events.patch create mode 100644 patches/server/0935-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch create mode 100644 patches/server/0936-Add-config-for-mobs-immune-to-default-effects.patch delete mode 100644 patches/server/0936-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch delete mode 100644 patches/server/0937-Add-config-for-mobs-immune-to-default-effects.patch create mode 100644 patches/server/0937-Deep-clone-nbt-tags-in-PDC.patch delete mode 100644 patches/server/0938-Deep-clone-nbt-tags-in-PDC.patch create mode 100644 patches/server/0938-Support-old-UUID-format-for-NBT.patch create mode 100644 patches/server/0939-Fix-shield-disable-inconsistency.patch delete mode 100644 patches/server/0939-Support-old-UUID-format-for-NBT.patch delete mode 100644 patches/server/0940-Fix-shield-disable-inconsistency.patch create mode 100644 patches/server/0940-Handle-Large-Packets-disconnecting-client.patch create mode 100644 patches/server/0941-Fix-ItemFlags.patch delete mode 100644 patches/server/0941-Handle-Large-Packets-disconnecting-client.patch delete mode 100644 patches/server/0942-Fix-ItemFlags.patch create mode 100644 patches/server/0942-Fix-damage-modifier-inconsistencies.patch delete mode 100644 patches/server/0943-Fix-damage-modifier-inconsistencies.patch create mode 100644 patches/server/0943-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch delete mode 100644 patches/server/0944-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch create mode 100644 patches/server/0944-improve-checking-handled-tags-in-itemmeta.patch create mode 100644 patches/server/0945-Expose-hasColor-to-leather-armor.patch delete mode 100644 patches/server/0945-improve-checking-handled-tags-in-itemmeta.patch create mode 100644 patches/server/0946-Added-API-to-get-player-ha-proxy-address.patch delete mode 100644 patches/server/0946-Expose-hasColor-to-leather-armor.patch delete mode 100644 patches/server/0947-Added-API-to-get-player-ha-proxy-address.patch create mode 100644 patches/server/0947-General-ItemMeta-fixes.patch delete mode 100644 patches/server/0948-General-ItemMeta-fixes.patch create mode 100644 patches/server/0948-More-Chest-Block-API.patch delete mode 100644 patches/server/0949-More-Chest-Block-API.patch create mode 100644 patches/server/0949-Print-data-component-type-on-encoding-error.patch create mode 100644 patches/server/0950-Brigadier-based-command-API.patch delete mode 100644 patches/server/0950-Print-data-component-type-on-encoding-error.patch delete mode 100644 patches/server/0951-Brigadier-based-command-API.patch create mode 100644 patches/server/0951-Fix-issues-with-Recipe-API.patch create mode 100644 patches/server/0952-Fix-equipment-slot-and-group-API.patch delete mode 100644 patches/server/0952-Fix-issues-with-Recipe-API.patch create mode 100644 patches/server/0953-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch delete mode 100644 patches/server/0953-Fix-equipment-slot-and-group-API.patch delete mode 100644 patches/server/0954-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch create mode 100644 patches/server/0954-Prevent-sending-oversized-item-data-in-equipment-and.patch create mode 100644 patches/server/0955-Prevent-NPE-if-hooked-entity-was-cleared.patch delete mode 100644 patches/server/0955-Prevent-sending-oversized-item-data-in-equipment-and.patch create mode 100644 patches/server/0956-Fix-cancelling-BlockPlaceEvent-calling-onRemove.patch delete mode 100644 patches/server/0956-Prevent-NPE-if-hooked-entity-was-cleared.patch create mode 100644 patches/server/0957-Add-missing-fishing-event-state.patch delete mode 100644 patches/server/0957-Fix-cancelling-BlockPlaceEvent-calling-onRemove.patch delete mode 100644 patches/server/0958-Add-missing-fishing-event-state.patch create mode 100644 patches/server/0958-Deprecate-InvAction-HOTBAR_MOVE_AND_READD.patch delete mode 100644 patches/server/0959-Deprecate-InvAction-HOTBAR_MOVE_AND_READD.patch create mode 100644 patches/server/0959-Fix-sending-disconnect-packet-in-phases-where-it-doe.patch create mode 100644 patches/server/0960-Adopt-MaterialRerouting.patch delete mode 100644 patches/server/0960-Fix-sending-disconnect-packet-in-phases-where-it-doe.patch delete mode 100644 patches/server/0961-Adopt-MaterialRerouting.patch create mode 100644 patches/server/0961-Suspicious-Effect-Entry-API.patch delete mode 100644 patches/server/0962-Suspicious-Effect-Entry-API.patch create mode 100644 patches/server/0962-check-if-itemstack-is-stackable-first.patch create mode 100644 patches/server/0963-Fix-removing-recipes-from-RecipeIterator.patch delete mode 100644 patches/server/0963-check-if-itemstack-is-stackable-first.patch create mode 100644 patches/server/0964-Configurable-damage-tick-when-blocking-with-shield.patch delete mode 100644 patches/server/0964-Fix-removing-recipes-from-RecipeIterator.patch delete mode 100644 patches/server/0965-Configurable-damage-tick-when-blocking-with-shield.patch create mode 100644 patches/server/0965-Properly-remove-the-experimental-smithing-inventory-.patch delete mode 100644 patches/server/0966-Properly-remove-the-experimental-smithing-inventory-.patch create mode 100644 patches/server/0966-disable-forced-empty-world-ticks.patch create mode 100644 patches/server/0967-Configurable-Sand-Duping.patch delete mode 100644 patches/server/0967-disable-forced-empty-world-ticks.patch delete mode 100644 patches/server/0968-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch create mode 100644 patches/server/0968-Proxy-ItemStack-to-CraftItemStack.patch delete mode 100644 patches/server/0969-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch create mode 100644 patches/server/0969-Make-a-PDC-view-accessible-directly-from-ItemStack.patch delete mode 100644 patches/server/0970-Optimize-Network-Manager-and-add-advanced-packet-sup.patch create mode 100644 patches/server/0970-Prioritize-Minecraft-commands-in-function-parsing-an.patch delete mode 100644 patches/server/0971-Allow-Saving-of-Oversized-Chunks.patch create mode 100644 patches/server/0971-Fix-NPE-for-Jukebox-setRecord.patch delete mode 100644 patches/server/0972-Flat-bedrock-generator-settings.patch create mode 100644 patches/server/0972-fix-horse-inventories.patch delete mode 100644 patches/server/0973-Entity-Activation-Range-2.0.patch create mode 100644 patches/server/0973-Only-call-EntityDamageEvents-before-actuallyHurt.patch create mode 100644 patches/server/0974-Add-ItemType-getItemRarity.patch delete mode 100644 patches/server/0974-Anti-Xray.patch create mode 100644 patches/server/0975-Add-plugin-info-at-startup.patch delete mode 100644 patches/server/0975-Use-Velocity-compression-and-cipher-natives.patch create mode 100644 patches/server/0976-Make-interaction-leniency-distance-configurable.patch delete mode 100644 patches/server/0976-Optimize-Collision-to-not-load-chunks.patch create mode 100644 patches/server/0977-Fix-PickupStatus-getting-reset.patch delete mode 100644 patches/server/0977-Optimize-GoalSelector-Goal.Flag-Set-operations.patch create mode 100644 patches/server/0978-Check-for-block-type-in-SculkSensorBlock-canActivate.patch delete mode 100644 patches/server/0978-Optimize-Hoppers.patch create mode 100644 patches/server/0979-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch delete mode 100644 patches/server/0979-Optimize-Voxel-Shape-Merging.patch create mode 100644 patches/server/0980-Configuration-for-horizontal-only-item-merging.patch delete mode 100644 patches/server/0980-Optimize-Bit-Operations-by-inlining.patch create mode 100644 patches/server/0981-Add-skipping-world-symlink-scan.patch delete mode 100644 patches/server/0981-Remove-streams-from-hot-code.patch create mode 100644 patches/server/0982-Add-even-more-Enchantment-API.patch delete mode 100644 patches/server/0982-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch delete mode 100644 patches/server/0983-Fix-entity-type-tags-suggestions-in-selectors.patch create mode 100644 patches/server/0983-Leashable-API.patch create mode 100644 patches/server/0984-Fix-CraftBukkit-drag-system.patch delete mode 100644 patches/server/0984-Handle-Oversized-block-entities-in-chunks.patch delete mode 100644 patches/server/0985-Check-distance-in-entity-interactions.patch create mode 100644 patches/server/0985-Fix-SculkBloomEvent-firing-for-block-entity-loading.patch delete mode 100644 patches/server/0986-Configurable-Sand-Duping.patch create mode 100644 patches/server/0986-Remove-set-damage-lootable-item-function-from-compas.patch create mode 100644 patches/server/0987-Add-enchantment-seed-update-API.patch delete mode 100644 patches/server/0987-Properly-resend-entities.patch create mode 100644 patches/server/0988-Fix-synchronise-sending-chat-to-client-with-updating.patch delete mode 100644 patches/server/0988-Registry-Modification-API.patch delete mode 100644 patches/server/0989-Add-registry-entry-and-builders.patch create mode 100644 patches/server/0989-Fix-InventoryOpenEvent-cancellation.patch create mode 100644 patches/server/0990-Fire-BlockExpEvent-on-grindstone-use.patch delete mode 100644 patches/server/0990-Proxy-ItemStack-to-CraftItemStack.patch create mode 100644 patches/server/0991-Check-dead-flag-in-isAlive.patch delete mode 100644 patches/server/0991-Make-a-PDC-view-accessible-directly-from-ItemStack.patch create mode 100644 patches/server/0992-Add-FeatureFlag-API.patch delete mode 100644 patches/server/0992-Prioritize-Minecraft-commands-in-function-parsing-an.patch create mode 100644 patches/server/0993-Item-serialization-as-json.patch delete mode 100644 patches/server/0993-optimize-dirt-and-snow-spreading.patch delete mode 100644 patches/server/0994-Fix-NPE-for-Jukebox-setRecord.patch create mode 100644 patches/server/0994-Validate-slot-in-PlayerInventory-setSlot.patch create mode 100644 patches/server/0995-Remove-wall-time-unused-skip-tick-protection.patch delete mode 100644 patches/server/0995-fix-horse-inventories.patch create mode 100644 patches/server/0996-Disable-pretty-printing-for-advancement-saving.patch delete mode 100644 patches/server/0996-Only-call-EntityDamageEvents-before-actuallyHurt.patch delete mode 100644 patches/server/0997-Add-ItemType-getItemRarity.patch create mode 100644 patches/server/0997-Fix-PlayerCommandPreprocessEvent-on-signed-commands.patch create mode 100644 patches/server/0998-Add-enchantWithLevels-with-enchantment-registry-set.patch delete mode 100644 patches/server/0998-Add-plugin-info-at-startup.patch create mode 100644 patches/server/0999-Improve-entity-effect-API.patch delete mode 100644 patches/server/0999-Make-interaction-leniency-distance-configurable.patch create mode 100644 patches/server/1000-Add-recipeBrewTime.patch delete mode 100644 patches/server/1000-Fix-PickupStatus-getting-reset.patch create mode 100644 patches/server/1001-Call-bucket-events-for-cauldrons.patch delete mode 100644 patches/server/1001-Check-for-block-type-in-SculkSensorBlock-canActivate.patch delete mode 100644 patches/server/1002-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch create mode 100644 patches/server/1002-Add-PlayerInsertLecternBookEvent.patch delete mode 100644 patches/server/1003-Configuration-for-horizontal-only-item-merging.patch create mode 100644 patches/server/1003-Void-damage-configuration-API.patch create mode 100644 patches/server/1004-Add-Offline-PDC-API.patch delete mode 100644 patches/server/1004-Add-skipping-world-symlink-scan.patch create mode 100644 patches/server/1005-Add-AnvilView-bypassEnchantmentLevelRestriction.patch delete mode 100644 patches/server/1005-Add-even-more-Enchantment-API.patch create mode 100644 patches/server/1006-Add-proper-async-player-disconnections.patch delete mode 100644 patches/server/1006-Leashable-API.patch delete mode 100644 patches/server/1007-Fix-CraftBukkit-drag-system.patch create mode 100644 patches/server/1007-Separate-dimensiondata-executor.patch create mode 100644 patches/server/1008-Always-send-Banner-patterns-to-the-client.patch delete mode 100644 patches/server/1008-Fix-SculkBloomEvent-firing-for-block-entity-loading.patch create mode 100644 patches/server/1009-API-for-checking-sent-chunks.patch delete mode 100644 patches/server/1009-Remove-set-damage-lootable-item-function-from-compas.patch delete mode 100644 patches/server/1010-Add-enchantment-seed-update-API.patch create mode 100644 patches/server/1010-Fix-CraftWorld-isChunkGenerated.patch create mode 100644 patches/server/1011-Add-startup-flag-to-disable-gamerule-limits.patch delete mode 100644 patches/server/1011-Fix-synchronise-sending-chat-to-client-with-updating.patch create mode 100644 patches/server/1012-Bundle-spark.patch delete mode 100644 patches/server/1012-Fix-InventoryOpenEvent-cancellation.patch create mode 100644 patches/server/1013-Avoid-issues-with-certain-tasks-not-processing-durin.patch delete mode 100644 patches/server/1013-Fire-BlockExpEvent-on-grindstone-use.patch create mode 100644 patches/server/1014-Allow-using-old-ender-pearl-behavior.patch delete mode 100644 patches/server/1014-Check-dead-flag-in-isAlive.patch delete mode 100644 patches/server/1015-Add-FeatureFlag-API.patch create mode 100644 patches/server/1015-Block-Enderpearl-Travel-Exploit.patch create mode 100644 patches/server/1016-Fix-inconsistencies-in-dispense-events-regarding-sta.patch delete mode 100644 patches/server/1016-Tag-Lifecycle-Events.patch create mode 100644 patches/server/1017-Correct-update-cursor.patch delete mode 100644 patches/server/1017-Item-serialization-as-json.patch create mode 100644 patches/server/1018-Call-CraftPlayer-onEntityRemove-for-all-online-playe.patch delete mode 100644 patches/server/1018-Validate-slot-in-PlayerInventory-setSlot.patch create mode 100644 patches/server/1019-Improve-performance-of-RecipeMap-removeRecipe.patch delete mode 100644 patches/server/1019-Remove-wall-time-unused-skip-tick-protection.patch delete mode 100644 patches/server/1020-Disable-pretty-printing-for-advancement-saving.patch create mode 100644 patches/server/1020-Reduce-work-done-in-CraftMapCanvas.drawImage-by-limi.patch delete mode 100644 patches/server/1021-Fix-PlayerCommandPreprocessEvent-on-signed-commands.patch create mode 100644 patches/server/1021-Fix-incorrect-invulnerability-damage-reduction.patch delete mode 100644 patches/server/1022-Add-enchantWithLevels-with-enchantment-registry-set.patch create mode 100644 patches/server/1022-Fix-NPE-when-EntityResurrectEvent-is-uncancelled.patch create mode 100644 patches/server/1023-API-to-check-if-the-server-is-sleeping.patch delete mode 100644 patches/server/1023-Improve-entity-effect-API.patch create mode 100644 patches/server/1024-API-to-allow-disallow-tick-sleeping.patch delete mode 100644 patches/server/1024-Add-recipeBrewTime.patch delete mode 100644 patches/server/1025-Call-bucket-events-for-cauldrons.patch create mode 100644 patches/server/1025-Configurable-Entity-Despawn-Time.patch delete mode 100644 patches/server/1026-Add-PlayerInsertLecternBookEvent.patch create mode 100644 patches/server/1026-Expanded-Art-API.patch create mode 100644 patches/server/1027-Only-attempt-to-find-spawn-position-if-there-isn-t-a.patch delete mode 100644 patches/server/1027-Void-damage-configuration-API.patch delete mode 100644 patches/server/1028-Add-Offline-PDC-API.patch create mode 100644 patches/server/1028-Registry-Modification-API.patch delete mode 100644 patches/server/1029-Add-AnvilView-bypassEnchantmentLevelRestriction.patch create mode 100644 patches/server/1029-Add-registry-entry-and-builders.patch delete mode 100644 patches/server/1030-Add-proper-async-player-disconnections.patch create mode 100644 patches/server/1030-Tag-Lifecycle-Events.patch create mode 100644 patches/server/1032-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch delete mode 100644 patches/server/1032-Separate-dimensiondata-executor.patch delete mode 100644 patches/server/1033-Always-send-Banner-patterns-to-the-client.patch create mode 100644 patches/server/1033-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch create mode 100644 patches/server/1034-Optimize-Network-Manager-and-add-advanced-packet-sup.patch delete mode 100644 patches/server/1034-Rewrite-dataconverter-system.patch create mode 100644 patches/server/1035-Allow-Saving-of-Oversized-Chunks.patch delete mode 100644 patches/server/1035-Moonrise-optimisation-patches.patch create mode 100644 patches/server/1036-Flat-bedrock-generator-settings.patch delete mode 100644 patches/server/1036-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch delete mode 100644 patches/server/1037-API-for-checking-sent-chunks.patch create mode 100644 patches/server/1037-Entity-Activation-Range-2.0.patch create mode 100644 patches/server/1038-Anti-Xray.patch delete mode 100644 patches/server/1038-Fix-CraftWorld-isChunkGenerated.patch delete mode 100644 patches/server/1039-Add-startup-flag-to-disable-gamerule-limits.patch create mode 100644 patches/server/1039-Use-Velocity-compression-and-cipher-natives.patch delete mode 100644 patches/server/1040-Improved-Watchdog-Support.patch create mode 100644 patches/server/1040-Optimize-Collision-to-not-load-chunks.patch delete mode 100644 patches/server/1041-Detail-more-information-in-watchdog-dumps.patch create mode 100644 patches/server/1041-Optimize-GoalSelector-Goal.Flag-Set-operations.patch delete mode 100644 patches/server/1042-Entity-load-save-limit-per-chunk.patch create mode 100644 patches/server/1042-Optimize-Hoppers.patch delete mode 100644 patches/server/1043-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch create mode 100644 patches/server/1043-Optimize-Voxel-Shape-Merging.patch delete mode 100644 patches/server/1044-Bundle-spark.patch create mode 100644 patches/server/1044-Optimize-Bit-Operations-by-inlining.patch delete mode 100644 patches/server/1045-Improve-performance-of-mass-crafts.patch create mode 100644 patches/server/1045-Remove-streams-from-hot-code.patch delete mode 100644 patches/server/1046-Incremental-chunk-and-player-saving.patch create mode 100644 patches/server/1046-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch create mode 100644 patches/server/1047-Fix-entity-type-tags-suggestions-in-selectors.patch delete mode 100644 patches/server/1047-Optimise-general-POI-access.patch delete mode 100644 patches/server/1048-Fix-entity-tracker-desync-when-new-players-are-added.patch create mode 100644 patches/server/1048-Handle-Oversized-block-entities-in-chunks.patch create mode 100644 patches/server/1049-Check-distance-in-entity-interactions.patch delete mode 100644 patches/server/1049-Lag-compensation-ticks.patch delete mode 100644 patches/server/1050-Optimise-collision-checking-in-player-move-packet-ha.patch create mode 100644 patches/server/1050-Properly-resend-entities.patch delete mode 100644 patches/server/1051-Optional-per-player-mob-spawns.patch create mode 100644 patches/server/1051-optimize-dirt-and-snow-spreading.patch delete mode 100644 patches/server/1052-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch create mode 100644 patches/server/1052-Optimise-getChunkAt-calls-for-loaded-chunks.patch delete mode 100644 patches/server/1053-Avoid-issues-with-certain-tasks-not-processing-durin.patch create mode 100644 patches/server/1053-Rewrite-dataconverter-system.patch delete mode 100644 patches/server/1054-Allow-using-old-ender-pearl-behavior.patch create mode 100644 patches/server/1054-Moonrise-optimisation-patches.patch delete mode 100644 patches/server/1055-Block-Enderpearl-Travel-Exploit.patch create mode 100644 patches/server/1055-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch delete mode 100644 patches/server/1056-Fix-inconsistencies-in-dispense-events-regarding-sta.patch create mode 100644 patches/server/1056-Improved-Watchdog-Support.patch delete mode 100644 patches/server/1057-Correct-update-cursor.patch create mode 100644 patches/server/1057-Detail-more-information-in-watchdog-dumps.patch delete mode 100644 patches/server/1058-Call-CraftPlayer-onEntityRemove-for-all-online-playe.patch create mode 100644 patches/server/1058-Entity-load-save-limit-per-chunk.patch create mode 100644 patches/server/1059-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch delete mode 100644 patches/server/1059-Eigencraft-redstone-implementation.patch delete mode 100644 patches/server/1060-Improve-performance-of-RecipeMap-removeRecipe.patch create mode 100644 patches/server/1060-Improve-performance-of-mass-crafts.patch create mode 100644 patches/server/1061-Incremental-chunk-and-player-saving.patch delete mode 100644 patches/server/1061-Reduce-work-done-in-CraftMapCanvas.drawImage-by-limi.patch delete mode 100644 patches/server/1062-Add-Alternate-Current-redstone-implementation.patch create mode 100644 patches/server/1062-Optimise-general-POI-access.patch create mode 100644 patches/server/1063-Fix-entity-tracker-desync-when-new-players-are-added.patch delete mode 100644 patches/server/1063-Fix-incorrect-invulnerability-damage-reduction.patch delete mode 100644 patches/server/1064-Fix-NPE-when-EntityResurrectEvent-is-uncancelled.patch create mode 100644 patches/server/1064-Lag-compensation-ticks.patch delete mode 100644 patches/server/1065-API-to-check-if-the-server-is-sleeping.patch create mode 100644 patches/server/1065-Optimise-collision-checking-in-player-move-packet-ha.patch delete mode 100644 patches/server/1066-API-to-allow-disallow-tick-sleeping.patch create mode 100644 patches/server/1066-Optional-per-player-mob-spawns.patch delete mode 100644 patches/server/1067-Configurable-Entity-Despawn-Time.patch create mode 100644 patches/server/1067-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch create mode 100644 patches/server/1068-Eigencraft-redstone-implementation.patch delete mode 100644 patches/server/1068-Expanded-Art-API.patch create mode 100644 patches/server/1069-Add-Alternate-Current-redstone-implementation.patch delete mode 100644 patches/server/1069-Only-attempt-to-find-spawn-position-if-there-isn-t-a.patch create mode 100644 patches/server/1071-Implement-chunk-view-API.patch diff --git a/patches/server/0009-MC-Utils.patch b/patches/server/0009-MC-Utils.patch index 00db4c45d0..89b8e3e9c8 100644 --- a/patches/server/0009-MC-Utils.patch +++ b/patches/server/0009-MC-Utils.patch @@ -2597,285 +2597,6 @@ index 0000000000000000000000000000000000000000..c2d917c2eac55b8a4411a6e159f177f9 + ((Runnable)TO_RUN_HANDLE.getVolatile(this)).run(); + } +} -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7e440b4a46b040365df7317035e577d93e7d855d ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java -@@ -0,0 +1,273 @@ -+package ca.spottedleaf.moonrise.common.misc; -+ -+import ca.spottedleaf.moonrise.common.list.ReferenceList; -+import ca.spottedleaf.moonrise.common.util.CoordinateUtils; -+import ca.spottedleaf.moonrise.common.util.MoonriseConstants; -+import ca.spottedleaf.moonrise.common.util.ChunkSystem; -+import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel; -+import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData; -+import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants; -+import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel; -+import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; -+import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -+import net.minecraft.core.BlockPos; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.level.ChunkPos; -+import java.util.ArrayList; -+ -+public final class NearbyPlayers { -+ -+ public static enum NearbyMapType { -+ GENERAL, -+ GENERAL_SMALL, -+ GENERAL_REALLY_SMALL, -+ TICK_VIEW_DISTANCE, -+ VIEW_DISTANCE, -+ // Moonrise start - chunk tick iteration -+ SPAWN_RANGE { -+ @Override -+ void addTo(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) { -+ ((ChunkTickServerLevel)world).moonrise$addPlayerTickingRequest(chunkX, chunkZ); -+ } -+ -+ @Override -+ void removeFrom(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) { -+ ((ChunkTickServerLevel)world).moonrise$removePlayerTickingRequest(chunkX, chunkZ); -+ } -+ }; -+ // Moonrise end - chunk tick iteration -+ -+ void addTo(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) { -+ -+ } -+ -+ void removeFrom(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) { -+ -+ } -+ } -+ -+ private static final NearbyMapType[] MAP_TYPES = NearbyMapType.values(); -+ public static final int TOTAL_MAP_TYPES = MAP_TYPES.length; -+ -+ private static final int GENERAL_AREA_VIEW_DISTANCE = MoonriseConstants.MAX_VIEW_DISTANCE + 1; -+ private static final int GENERAL_SMALL_VIEW_DISTANCE = 10; -+ private static final int GENERAL_REALLY_SMALL_VIEW_DISTANCE = 3; -+ -+ public static final int GENERAL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_AREA_VIEW_DISTANCE << 4); -+ public static final int GENERAL_SMALL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_SMALL_VIEW_DISTANCE << 4); -+ public static final int GENERAL_REALLY_SMALL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_REALLY_SMALL_VIEW_DISTANCE << 4); -+ -+ private final ServerLevel world; -+ private final Reference2ReferenceOpenHashMap players = new Reference2ReferenceOpenHashMap<>(); -+ private final Long2ReferenceOpenHashMap byChunk = new Long2ReferenceOpenHashMap<>(); -+ private final Long2ReferenceOpenHashMap>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES]; -+ { -+ for (int i = 0; i < this.directByChunk.length; ++i) { -+ this.directByChunk[i] = new Long2ReferenceOpenHashMap<>(); -+ } -+ } -+ -+ public NearbyPlayers(final ServerLevel world) { -+ this.world = world; -+ } -+ -+ public void addPlayer(final ServerPlayer player) { -+ final TrackedPlayer[] newTrackers = new TrackedPlayer[TOTAL_MAP_TYPES]; -+ if (this.players.putIfAbsent(player, newTrackers) != null) { -+ throw new IllegalStateException("Already have player " + player); -+ } -+ -+ final ChunkPos chunk = player.chunkPosition(); -+ -+ for (int i = 0; i < TOTAL_MAP_TYPES; ++i) { -+ // use 0 for default, will be updated by tickPlayer -+ (newTrackers[i] = new TrackedPlayer(player, MAP_TYPES[i])).add(chunk.x, chunk.z, 0); -+ } -+ -+ // update view distances -+ this.tickPlayer(player); -+ } -+ -+ public void removePlayer(final ServerPlayer player) { -+ final TrackedPlayer[] players = this.players.remove(player); -+ if (players == null) { -+ return; // May be called during teleportation before the player is actually placed -+ } -+ -+ for (final TrackedPlayer tracker : players) { -+ tracker.remove(); -+ } -+ } -+ -+ public void clear() { -+ if (this.players.isEmpty()) { -+ return; -+ } -+ -+ for (final ServerPlayer player : new ArrayList<>(this.players.keySet())) { -+ this.removePlayer(player); -+ } -+ } -+ -+ public void tickPlayer(final ServerPlayer player) { -+ final TrackedPlayer[] players = this.players.get(player); -+ if (players == null) { -+ throw new IllegalStateException("Don't have player " + player); -+ } -+ -+ final ChunkPos chunk = player.chunkPosition(); -+ -+ players[NearbyMapType.GENERAL.ordinal()].update(chunk.x, chunk.z, GENERAL_AREA_VIEW_DISTANCE); -+ players[NearbyMapType.GENERAL_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_SMALL_VIEW_DISTANCE); -+ players[NearbyMapType.GENERAL_REALLY_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_REALLY_SMALL_VIEW_DISTANCE); -+ players[NearbyMapType.TICK_VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getTickViewDistance(player)); -+ players[NearbyMapType.VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getViewDistance(player)); -+ players[NearbyMapType.SPAWN_RANGE.ordinal()].update(chunk.x, chunk.z, ChunkTickConstants.PLAYER_SPAWN_TRACK_RANGE); // Moonrise - chunk tick iteration -+ } -+ -+ public TrackedChunk getChunk(final ChunkPos pos) { -+ return this.byChunk.get(CoordinateUtils.getChunkKey(pos)); -+ } -+ -+ public TrackedChunk getChunk(final BlockPos pos) { -+ return this.byChunk.get(CoordinateUtils.getChunkKey(pos)); -+ } -+ -+ public TrackedChunk getChunk(final int chunkX, final int chunkZ) { -+ return this.byChunk.get(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ } -+ -+ public ReferenceList getPlayers(final BlockPos pos, final NearbyMapType type) { -+ return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(pos)); -+ } -+ -+ public ReferenceList getPlayers(final ChunkPos pos, final NearbyMapType type) { -+ return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(pos)); -+ } -+ -+ public ReferenceList getPlayersByChunk(final int chunkX, final int chunkZ, final NearbyMapType type) { -+ return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ } -+ -+ public ReferenceList getPlayersByBlock(final int blockX, final int blockZ, final NearbyMapType type) { -+ return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(blockX >> 4, blockZ >> 4)); -+ } -+ -+ public static final class TrackedChunk { -+ -+ private static final ServerPlayer[] EMPTY_PLAYERS_ARRAY = new ServerPlayer[0]; -+ -+ private final long chunkKey; -+ private final NearbyPlayers nearbyPlayers; -+ private final ReferenceList[] players = new ReferenceList[TOTAL_MAP_TYPES]; -+ private int nonEmptyLists; -+ private long updateCount; -+ -+ public TrackedChunk(final long chunkKey, final NearbyPlayers nearbyPlayers) { -+ this.chunkKey = chunkKey; -+ this.nearbyPlayers = nearbyPlayers; -+ } -+ -+ public boolean isEmpty() { -+ return this.nonEmptyLists == 0; -+ } -+ -+ public long getUpdateCount() { -+ return this.updateCount; -+ } -+ -+ public ReferenceList getPlayers(final NearbyMapType type) { -+ return this.players[type.ordinal()]; -+ } -+ -+ public void addPlayer(final ServerPlayer player, final NearbyMapType type) { -+ ++this.updateCount; -+ -+ final int idx = type.ordinal(); -+ final ReferenceList list = this.players[idx]; -+ if (list == null) { -+ ++this.nonEmptyLists; -+ final ReferenceList players = (this.players[idx] = new ReferenceList<>(EMPTY_PLAYERS_ARRAY)); -+ this.nearbyPlayers.directByChunk[idx].put(this.chunkKey, players); -+ players.add(player); -+ return; -+ } -+ -+ if (!list.add(player)) { -+ throw new IllegalStateException("Already contains player " + player); -+ } -+ } -+ -+ public void removePlayer(final ServerPlayer player, final NearbyMapType type) { -+ ++this.updateCount; -+ -+ final int idx = type.ordinal(); -+ final ReferenceList list = this.players[idx]; -+ if (list == null) { -+ throw new IllegalStateException("Does not contain player " + player); -+ } -+ -+ if (!list.remove(player)) { -+ throw new IllegalStateException("Does not contain player " + player); -+ } -+ -+ if (list.size() == 0) { -+ this.players[idx] = null; -+ this.nearbyPlayers.directByChunk[idx].remove(this.chunkKey); -+ --this.nonEmptyLists; -+ } -+ } -+ } -+ -+ private final class TrackedPlayer extends SingleUserAreaMap { -+ -+ private final NearbyMapType type; -+ -+ public TrackedPlayer(final ServerPlayer player, final NearbyMapType type) { -+ super(player); -+ this.type = type; -+ } -+ -+ @Override -+ protected void addCallback(final ServerPlayer parameter, final int chunkX, final int chunkZ) { -+ final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ); -+ -+ final TrackedChunk chunk = NearbyPlayers.this.byChunk.get(chunkKey); -+ final NearbyMapType type = this.type; -+ if (chunk != null) { -+ chunk.addPlayer(parameter, type); -+ type.addTo(parameter, NearbyPlayers.this.world, chunkX, chunkZ); -+ } else { -+ final TrackedChunk created = new TrackedChunk(chunkKey, NearbyPlayers.this); -+ NearbyPlayers.this.byChunk.put(chunkKey, created); -+ created.addPlayer(parameter, type); -+ type.addTo(parameter, NearbyPlayers.this.world, chunkX, chunkZ); -+ -+ ((ChunkSystemLevel)NearbyPlayers.this.world).moonrise$requestChunkData(chunkKey).nearbyPlayers = created; -+ } -+ } -+ -+ @Override -+ protected void removeCallback(final ServerPlayer parameter, final int chunkX, final int chunkZ) { -+ final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ); -+ -+ final TrackedChunk chunk = NearbyPlayers.this.byChunk.get(chunkKey); -+ if (chunk == null) { -+ throw new IllegalStateException("Chunk should exist at " + new ChunkPos(chunkKey)); -+ } -+ -+ final NearbyMapType type = this.type; -+ chunk.removePlayer(parameter, type); -+ type.removeFrom(parameter, NearbyPlayers.this.world, chunkX, chunkZ); -+ -+ if (chunk.isEmpty()) { -+ NearbyPlayers.this.byChunk.remove(chunkKey); -+ final ChunkData chunkData = ((ChunkSystemLevel)NearbyPlayers.this.world).moonrise$releaseChunkData(chunkKey); -+ if (chunkData != null) { -+ chunkData.nearbyPlayers = null; -+ } -+ } -+ } -+ } -+} diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/PositionCountingAreaMap.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/PositionCountingAreaMap.java new file mode 100644 index 0000000000000000000000000000000000000000..90560769d09538f7a740753a41a3b8e017b0b92a @@ -5625,7 +5346,7 @@ index 9cdcab885a915990a679f3fc9ae6885f7d125bfd..3e35a64b4b92ec25789e85c7445375dd boolean flag1 = this.chunkMap.promoteChunkMap(); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index ecbef5d54aef8e3f3bc2e4c34d2da6e96b1267b8..cba44ea8375692ce9d2511fba1ac1dd1d2d0cb1e 100644 +index 7ccf5329d6c4db1a9cfb78f07d5bdf982185240f..ca112107e2c3b66f18b0a4517dc85bc4c95888dc 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -240,6 +240,103 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe diff --git a/patches/server/0308-Add-debug-for-sync-chunk-loads.patch b/patches/server/0308-Add-debug-for-sync-chunk-loads.patch new file mode 100644 index 0000000000..11fb05a7eb --- /dev/null +++ b/patches/server/0308-Add-debug-for-sync-chunk-loads.patch @@ -0,0 +1,333 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Fri, 19 Jul 2019 03:29:14 -0700 +Subject: [PATCH] Add debug for sync chunk loads + +This patch adds a tool to find calls to getChunkAt which would load +chunks, however it must be enabled by setting the startup flag +-Dpaper.debug-sync-loads=true + +- To get a debug log for sync loads, the command is + /paper syncloadinfo +- To clear clear the currently stored sync load info, use + /paper syncloadinfo clear + +diff --git a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..605a4a83d0a098a9977da00c710e798396dc5256 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java +@@ -0,0 +1,177 @@ ++package com.destroystokyo.paper.io; ++ ++import com.google.gson.JsonArray; ++import com.google.gson.JsonObject; ++import com.mojang.datafixers.util.Pair; ++import it.unimi.dsi.fastutil.longs.Long2IntMap; ++import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; ++import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; ++ ++import java.util.ArrayList; ++import java.util.List; ++import java.util.Map; ++import java.util.WeakHashMap; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.Level; ++ ++public class SyncLoadFinder { ++ ++ public static final boolean ENABLED = Boolean.getBoolean("paper.debug-sync-loads"); ++ ++ private static final WeakHashMap> SYNC_LOADS = new WeakHashMap<>(); ++ ++ private static final class SyncLoadInformation { ++ ++ public int times; ++ ++ public final Long2IntOpenHashMap coordinateTimes = new Long2IntOpenHashMap(); ++ } ++ ++ public static void clear() { ++ SYNC_LOADS.clear(); ++ } ++ ++ public static void logSyncLoad(final Level world, final int chunkX, final int chunkZ) { ++ if (!ENABLED) { ++ return; ++ } ++ ++ final ThrowableWithEquals stacktrace = new ThrowableWithEquals(Thread.currentThread().getStackTrace()); ++ ++ SYNC_LOADS.compute(world, (final Level keyInMap, Object2ObjectOpenHashMap map) -> { ++ if (map == null) { ++ map = new Object2ObjectOpenHashMap<>(); ++ } ++ ++ map.compute(stacktrace, (ThrowableWithEquals keyInMap0, SyncLoadInformation valueInMap) -> { ++ if (valueInMap == null) { ++ valueInMap = new SyncLoadInformation(); ++ } ++ ++ ++valueInMap.times; ++ ++ valueInMap.coordinateTimes.compute(ChunkPos.asLong(chunkX, chunkZ), (Long keyInMap1, Integer valueInMap1) -> { ++ return valueInMap1 == null ? Integer.valueOf(1) : Integer.valueOf(valueInMap1.intValue() + 1); ++ }); ++ ++ return valueInMap; ++ }); ++ ++ return map; ++ }); ++ } ++ ++ public static JsonObject serialize() { ++ final JsonObject ret = new JsonObject(); ++ ++ final JsonArray worldsData = new JsonArray(); ++ ++ for (final Map.Entry> entry : SYNC_LOADS.entrySet()) { ++ final Level world = entry.getKey(); ++ ++ final JsonObject worldData = new JsonObject(); ++ ++ worldData.addProperty("name", world.getWorld().getName()); ++ ++ final List> data = new ArrayList<>(); ++ ++ entry.getValue().forEach((ThrowableWithEquals stacktrace, SyncLoadInformation times) -> { ++ data.add(new Pair<>(stacktrace, times)); ++ }); ++ ++ data.sort((Pair pair1, Pair pair2) -> { ++ return Integer.compare(pair2.getSecond().times, pair1.getSecond().times); // reverse order ++ }); ++ ++ final JsonArray stacktraces = new JsonArray(); ++ ++ for (Pair pair : data) { ++ final JsonObject stacktrace = new JsonObject(); ++ ++ stacktrace.addProperty("times", pair.getSecond().times); ++ ++ final JsonArray traces = new JsonArray(); ++ ++ for (StackTraceElement element : pair.getFirst().stacktrace) { ++ traces.add(String.valueOf(element)); ++ } ++ ++ stacktrace.add("stacktrace", traces); ++ ++ final JsonArray coordinates = new JsonArray(); ++ ++ for (Long2IntMap.Entry coordinate : pair.getSecond().coordinateTimes.long2IntEntrySet()) { ++ final long key = coordinate.getLongKey(); ++ final int times = coordinate.getIntValue(); ++ final ChunkPos chunkPos = new ChunkPos(key); ++ coordinates.add("(" + chunkPos.x + "," + chunkPos.z + "): " + times); ++ } ++ ++ stacktrace.add("coordinates", coordinates); ++ ++ stacktraces.add(stacktrace); ++ } ++ ++ ++ worldData.add("stacktraces", stacktraces); ++ worldsData.add(worldData); ++ } ++ ++ ret.add("worlds", worldsData); ++ ++ return ret; ++ } ++ ++ static final class ThrowableWithEquals { ++ ++ private final StackTraceElement[] stacktrace; ++ private final int hash; ++ ++ public ThrowableWithEquals(final StackTraceElement[] stacktrace) { ++ this.stacktrace = stacktrace; ++ this.hash = ThrowableWithEquals.hash(stacktrace); ++ } ++ ++ public static int hash(final StackTraceElement[] stacktrace) { ++ int hash = 0; ++ ++ for (int i = 0; i < stacktrace.length; ++i) { ++ hash *= 31; ++ hash += stacktrace[i].hashCode(); ++ } ++ ++ return hash; ++ } ++ ++ @Override ++ public int hashCode() { ++ return this.hash; ++ } ++ ++ @Override ++ public boolean equals(final Object obj) { ++ if (obj == null || obj.getClass() != this.getClass()) { ++ return false; ++ } ++ ++ final ThrowableWithEquals other = (ThrowableWithEquals)obj; ++ final StackTraceElement[] otherStackTrace = other.stacktrace; ++ ++ if (this.stacktrace.length != otherStackTrace.length || this.hash != other.hash) { ++ return false; ++ } ++ ++ if (this == obj) { ++ return true; ++ } ++ ++ for (int i = 0; i < this.stacktrace.length; ++i) { ++ if (!this.stacktrace[i].equals(otherStackTrace[i])) { ++ return false; ++ } ++ } ++ ++ return true; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java +index e1820a339452cd3388dd7cbb928c5f58779a77b6..3010d57efcc97fb409bfe43b1fc9af198c099a67 100644 +--- a/src/main/java/io/papermc/paper/command/PaperCommand.java ++++ b/src/main/java/io/papermc/paper/command/PaperCommand.java +@@ -38,6 +38,7 @@ public final class PaperCommand extends Command { + commands.put(Set.of("reload"), new ReloadCommand()); + commands.put(Set.of("version"), new VersionCommand()); + commands.put(Set.of("dumpplugins"), new DumpPluginsCommand()); ++ commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); + + 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/SyncLoadInfoCommand.java b/src/main/java/io/papermc/paper/command/subcommands/SyncLoadInfoCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..95d6022c9cfb2e36ec5a71be6e34354027c2ec08 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/subcommands/SyncLoadInfoCommand.java +@@ -0,0 +1,88 @@ ++package io.papermc.paper.command.subcommands; ++ ++import com.destroystokyo.paper.io.SyncLoadFinder; ++import com.google.gson.JsonObject; ++import com.google.gson.internal.Streams; ++import com.google.gson.stream.JsonWriter; ++import io.papermc.paper.command.CommandUtil; ++import io.papermc.paper.command.PaperSubcommand; ++import java.io.File; ++import java.io.FileOutputStream; ++import java.io.PrintStream; ++import java.io.StringWriter; ++import java.nio.charset.StandardCharsets; ++import java.time.LocalDateTime; ++import java.time.format.DateTimeFormatter; ++import java.util.List; ++ ++import net.kyori.adventure.text.event.ClickEvent; ++import net.kyori.adventure.text.event.HoverEvent; ++import net.minecraft.server.MinecraftServer; ++import org.bukkit.command.CommandSender; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++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 SyncLoadInfoCommand implements PaperSubcommand { ++ @Override ++ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { ++ this.doSyncLoadInfo(sender, args); ++ return true; ++ } ++ ++ @Override ++ public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { ++ return CommandUtil.getListMatchingLast(sender, args, "clear"); ++ } ++ ++ private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss"); ++ ++ private void doSyncLoadInfo(final CommandSender sender, final String[] args) { ++ if (!SyncLoadFinder.ENABLED) { ++ String systemFlag = "-Dpaper.debug-sync-loads=true"; ++ sender.sendMessage(text().color(RED).append(text("This command requires the server startup flag '")).append( ++ text(systemFlag, WHITE).clickEvent(ClickEvent.copyToClipboard(systemFlag)) ++ .hoverEvent(HoverEvent.showText(text("Click to copy the system flag")))).append( ++ text("' to be set."))); ++ return; ++ } ++ ++ if (args.length > 0 && args[0].equals("clear")) { ++ SyncLoadFinder.clear(); ++ sender.sendMessage(text("Sync load data cleared.", GRAY)); ++ return; ++ } ++ ++ File file = new File(new File(new File("."), "debug"), ++ "sync-load-info-" + FORMATTER.format(LocalDateTime.now()) + ".txt"); ++ file.getParentFile().mkdirs(); ++ sender.sendMessage(text("Writing sync load info to " + file, GREEN)); ++ ++ ++ try { ++ final JsonObject data = SyncLoadFinder.serialize(); ++ ++ StringWriter stringWriter = new StringWriter(); ++ JsonWriter jsonWriter = new JsonWriter(stringWriter); ++ jsonWriter.setIndent(" "); ++ jsonWriter.setLenient(false); ++ Streams.write(data, jsonWriter); ++ ++ try ( ++ PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8) ++ ) { ++ out.print(stringWriter); ++ } ++ sender.sendMessage(text("Successfully written sync load information!", GREEN)); ++ } catch (Throwable thr) { ++ sender.sendMessage(text("Failed to write sync load information! See the console for more info.", RED)); ++ MinecraftServer.LOGGER.warn("Error occurred while dumping sync chunk load info", thr); ++ } ++ } ++} +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index f4fa64ab18573cb9a22a9bfb79a351c388d1aaa5..df51c80b73e9922e4b0a1f2291ebabbb74d809ff 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -215,6 +215,7 @@ public class ServerChunkCache extends ChunkSource { + + Objects.requireNonNull(completablefuture); + chunkproviderserver_b.managedBlock(completablefuture::isDone); ++ // com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads + ChunkResult 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 6b97e29b0102b5521cba424f008478245c67d85f..5b47505353bf96bcb555910d1ebf645d14052f46 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -416,6 +416,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit + } + ++ // Paper start ++ @Override ++ public boolean hasChunk(int chunkX, int chunkZ) { ++ return this.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ) != null; ++ } ++ // Paper end ++ + /** @deprecated */ + @Deprecated + @VisibleForTesting diff --git a/patches/server/0308-Optimise-getChunkAt-calls-for-loaded-chunks.patch b/patches/server/0308-Optimise-getChunkAt-calls-for-loaded-chunks.patch deleted file mode 100644 index 45e56cdb47..0000000000 --- a/patches/server/0308-Optimise-getChunkAt-calls-for-loaded-chunks.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 25 Jan 2020 17:04:35 -0800 -Subject: [PATCH] Optimise getChunkAt calls for loaded chunks - -bypass the need to get a player chunk, then get the either, -then unwrap it... - -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index f4fa64ab18573cb9a22a9bfb79a351c388d1aaa5..2bd7f0554bdf668930c990156f65e97e4b64d8bc 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -194,6 +194,12 @@ public class ServerChunkCache extends ChunkSource { - return this.getChunk(x, z, leastStatus, create); - }, this.mainThreadProcessor).join(); - } else { -+ // Paper start - Perf: Optimise getChunkAt calls for loaded chunks -+ LevelChunk ifLoaded = this.getChunkAtIfLoadedMainThread(x, z); -+ if (ifLoaded != null) { -+ return ifLoaded; -+ } -+ // Paper end - Perf: Optimise getChunkAt calls for loaded chunks - ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.incrementCounter("getChunk"); -@@ -233,33 +239,7 @@ public class ServerChunkCache extends ChunkSource { - if (Thread.currentThread() != this.mainThread) { - return null; - } else { -- Profiler.get().incrementCounter("getChunkNow"); -- long k = ChunkPos.asLong(chunkX, chunkZ); -- -- ChunkAccess ichunkaccess; -- -- for (int l = 0; l < 4; ++l) { -- if (k == this.lastChunkPos[l] && this.lastChunkStatus[l] == ChunkStatus.FULL) { -- ichunkaccess = this.lastChunk[l]; -- return ichunkaccess instanceof LevelChunk ? (LevelChunk) ichunkaccess : null; -- } -- } -- -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k); -- -- if (playerchunk == null) { -- return null; -- } else { -- ichunkaccess = playerchunk.getChunkIfPresent(ChunkStatus.FULL); -- if (ichunkaccess != null) { -- this.storeInCache(k, ichunkaccess, ChunkStatus.FULL); -- if (ichunkaccess instanceof LevelChunk) { -- return (LevelChunk) ichunkaccess; -- } -- } -- -- return null; -- } -+ return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks - } - } - diff --git a/patches/server/0309-Add-debug-for-sync-chunk-loads.patch b/patches/server/0309-Add-debug-for-sync-chunk-loads.patch deleted file mode 100644 index f3652f680c..0000000000 --- a/patches/server/0309-Add-debug-for-sync-chunk-loads.patch +++ /dev/null @@ -1,333 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Fri, 19 Jul 2019 03:29:14 -0700 -Subject: [PATCH] Add debug for sync chunk loads - -This patch adds a tool to find calls to getChunkAt which would load -chunks, however it must be enabled by setting the startup flag --Dpaper.debug-sync-loads=true - -- To get a debug log for sync loads, the command is - /paper syncloadinfo -- To clear clear the currently stored sync load info, use - /paper syncloadinfo clear - -diff --git a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java -new file mode 100644 -index 0000000000000000000000000000000000000000..605a4a83d0a098a9977da00c710e798396dc5256 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java -@@ -0,0 +1,177 @@ -+package com.destroystokyo.paper.io; -+ -+import com.google.gson.JsonArray; -+import com.google.gson.JsonObject; -+import com.mojang.datafixers.util.Pair; -+import it.unimi.dsi.fastutil.longs.Long2IntMap; -+import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -+ -+import java.util.ArrayList; -+import java.util.List; -+import java.util.Map; -+import java.util.WeakHashMap; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.Level; -+ -+public class SyncLoadFinder { -+ -+ public static final boolean ENABLED = Boolean.getBoolean("paper.debug-sync-loads"); -+ -+ private static final WeakHashMap> SYNC_LOADS = new WeakHashMap<>(); -+ -+ private static final class SyncLoadInformation { -+ -+ public int times; -+ -+ public final Long2IntOpenHashMap coordinateTimes = new Long2IntOpenHashMap(); -+ } -+ -+ public static void clear() { -+ SYNC_LOADS.clear(); -+ } -+ -+ public static void logSyncLoad(final Level world, final int chunkX, final int chunkZ) { -+ if (!ENABLED) { -+ return; -+ } -+ -+ final ThrowableWithEquals stacktrace = new ThrowableWithEquals(Thread.currentThread().getStackTrace()); -+ -+ SYNC_LOADS.compute(world, (final Level keyInMap, Object2ObjectOpenHashMap map) -> { -+ if (map == null) { -+ map = new Object2ObjectOpenHashMap<>(); -+ } -+ -+ map.compute(stacktrace, (ThrowableWithEquals keyInMap0, SyncLoadInformation valueInMap) -> { -+ if (valueInMap == null) { -+ valueInMap = new SyncLoadInformation(); -+ } -+ -+ ++valueInMap.times; -+ -+ valueInMap.coordinateTimes.compute(ChunkPos.asLong(chunkX, chunkZ), (Long keyInMap1, Integer valueInMap1) -> { -+ return valueInMap1 == null ? Integer.valueOf(1) : Integer.valueOf(valueInMap1.intValue() + 1); -+ }); -+ -+ return valueInMap; -+ }); -+ -+ return map; -+ }); -+ } -+ -+ public static JsonObject serialize() { -+ final JsonObject ret = new JsonObject(); -+ -+ final JsonArray worldsData = new JsonArray(); -+ -+ for (final Map.Entry> entry : SYNC_LOADS.entrySet()) { -+ final Level world = entry.getKey(); -+ -+ final JsonObject worldData = new JsonObject(); -+ -+ worldData.addProperty("name", world.getWorld().getName()); -+ -+ final List> data = new ArrayList<>(); -+ -+ entry.getValue().forEach((ThrowableWithEquals stacktrace, SyncLoadInformation times) -> { -+ data.add(new Pair<>(stacktrace, times)); -+ }); -+ -+ data.sort((Pair pair1, Pair pair2) -> { -+ return Integer.compare(pair2.getSecond().times, pair1.getSecond().times); // reverse order -+ }); -+ -+ final JsonArray stacktraces = new JsonArray(); -+ -+ for (Pair pair : data) { -+ final JsonObject stacktrace = new JsonObject(); -+ -+ stacktrace.addProperty("times", pair.getSecond().times); -+ -+ final JsonArray traces = new JsonArray(); -+ -+ for (StackTraceElement element : pair.getFirst().stacktrace) { -+ traces.add(String.valueOf(element)); -+ } -+ -+ stacktrace.add("stacktrace", traces); -+ -+ final JsonArray coordinates = new JsonArray(); -+ -+ for (Long2IntMap.Entry coordinate : pair.getSecond().coordinateTimes.long2IntEntrySet()) { -+ final long key = coordinate.getLongKey(); -+ final int times = coordinate.getIntValue(); -+ final ChunkPos chunkPos = new ChunkPos(key); -+ coordinates.add("(" + chunkPos.x + "," + chunkPos.z + "): " + times); -+ } -+ -+ stacktrace.add("coordinates", coordinates); -+ -+ stacktraces.add(stacktrace); -+ } -+ -+ -+ worldData.add("stacktraces", stacktraces); -+ worldsData.add(worldData); -+ } -+ -+ ret.add("worlds", worldsData); -+ -+ return ret; -+ } -+ -+ static final class ThrowableWithEquals { -+ -+ private final StackTraceElement[] stacktrace; -+ private final int hash; -+ -+ public ThrowableWithEquals(final StackTraceElement[] stacktrace) { -+ this.stacktrace = stacktrace; -+ this.hash = ThrowableWithEquals.hash(stacktrace); -+ } -+ -+ public static int hash(final StackTraceElement[] stacktrace) { -+ int hash = 0; -+ -+ for (int i = 0; i < stacktrace.length; ++i) { -+ hash *= 31; -+ hash += stacktrace[i].hashCode(); -+ } -+ -+ return hash; -+ } -+ -+ @Override -+ public int hashCode() { -+ return this.hash; -+ } -+ -+ @Override -+ public boolean equals(final Object obj) { -+ if (obj == null || obj.getClass() != this.getClass()) { -+ return false; -+ } -+ -+ final ThrowableWithEquals other = (ThrowableWithEquals)obj; -+ final StackTraceElement[] otherStackTrace = other.stacktrace; -+ -+ if (this.stacktrace.length != otherStackTrace.length || this.hash != other.hash) { -+ return false; -+ } -+ -+ if (this == obj) { -+ return true; -+ } -+ -+ for (int i = 0; i < this.stacktrace.length; ++i) { -+ if (!this.stacktrace[i].equals(otherStackTrace[i])) { -+ return false; -+ } -+ } -+ -+ return true; -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java -index e1820a339452cd3388dd7cbb928c5f58779a77b6..3010d57efcc97fb409bfe43b1fc9af198c099a67 100644 ---- a/src/main/java/io/papermc/paper/command/PaperCommand.java -+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java -@@ -38,6 +38,7 @@ public final class PaperCommand extends Command { - commands.put(Set.of("reload"), new ReloadCommand()); - commands.put(Set.of("version"), new VersionCommand()); - commands.put(Set.of("dumpplugins"), new DumpPluginsCommand()); -+ commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); - - 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/SyncLoadInfoCommand.java b/src/main/java/io/papermc/paper/command/subcommands/SyncLoadInfoCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..95d6022c9cfb2e36ec5a71be6e34354027c2ec08 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/subcommands/SyncLoadInfoCommand.java -@@ -0,0 +1,88 @@ -+package io.papermc.paper.command.subcommands; -+ -+import com.destroystokyo.paper.io.SyncLoadFinder; -+import com.google.gson.JsonObject; -+import com.google.gson.internal.Streams; -+import com.google.gson.stream.JsonWriter; -+import io.papermc.paper.command.CommandUtil; -+import io.papermc.paper.command.PaperSubcommand; -+import java.io.File; -+import java.io.FileOutputStream; -+import java.io.PrintStream; -+import java.io.StringWriter; -+import java.nio.charset.StandardCharsets; -+import java.time.LocalDateTime; -+import java.time.format.DateTimeFormatter; -+import java.util.List; -+ -+import net.kyori.adventure.text.event.ClickEvent; -+import net.kyori.adventure.text.event.HoverEvent; -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.command.CommandSender; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+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 SyncLoadInfoCommand implements PaperSubcommand { -+ @Override -+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ this.doSyncLoadInfo(sender, args); -+ return true; -+ } -+ -+ @Override -+ public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { -+ return CommandUtil.getListMatchingLast(sender, args, "clear"); -+ } -+ -+ private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss"); -+ -+ private void doSyncLoadInfo(final CommandSender sender, final String[] args) { -+ if (!SyncLoadFinder.ENABLED) { -+ String systemFlag = "-Dpaper.debug-sync-loads=true"; -+ sender.sendMessage(text().color(RED).append(text("This command requires the server startup flag '")).append( -+ text(systemFlag, WHITE).clickEvent(ClickEvent.copyToClipboard(systemFlag)) -+ .hoverEvent(HoverEvent.showText(text("Click to copy the system flag")))).append( -+ text("' to be set."))); -+ return; -+ } -+ -+ if (args.length > 0 && args[0].equals("clear")) { -+ SyncLoadFinder.clear(); -+ sender.sendMessage(text("Sync load data cleared.", GRAY)); -+ return; -+ } -+ -+ File file = new File(new File(new File("."), "debug"), -+ "sync-load-info-" + FORMATTER.format(LocalDateTime.now()) + ".txt"); -+ file.getParentFile().mkdirs(); -+ sender.sendMessage(text("Writing sync load info to " + file, GREEN)); -+ -+ -+ try { -+ final JsonObject data = SyncLoadFinder.serialize(); -+ -+ StringWriter stringWriter = new StringWriter(); -+ JsonWriter jsonWriter = new JsonWriter(stringWriter); -+ jsonWriter.setIndent(" "); -+ jsonWriter.setLenient(false); -+ Streams.write(data, jsonWriter); -+ -+ try ( -+ PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8) -+ ) { -+ out.print(stringWriter); -+ } -+ sender.sendMessage(text("Successfully written sync load information!", GREEN)); -+ } catch (Throwable thr) { -+ sender.sendMessage(text("Failed to write sync load information! See the console for more info.", RED)); -+ MinecraftServer.LOGGER.warn("Error occurred while dumping sync chunk load info", thr); -+ } -+ } -+} -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 2bd7f0554bdf668930c990156f65e97e4b64d8bc..6a2af3cd3aebe525a5ff41a801929547d59b8fec 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -221,6 +221,7 @@ public class ServerChunkCache extends ChunkSource { - - Objects.requireNonNull(completablefuture); - chunkproviderserver_b.managedBlock(completablefuture::isDone); -+ // com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads - ChunkResult 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 6430e759c3d89033418f79c7f7aacb8ca5a5135b..578d284a3e39368c5285eafe84056b081a240e3d 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -416,6 +416,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit - } - -+ // Paper start -+ @Override -+ public boolean hasChunk(int chunkX, int chunkZ) { -+ return this.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ) != null; -+ } -+ // Paper end -+ - /** @deprecated */ - @Deprecated - @VisibleForTesting diff --git a/patches/server/0309-Improve-java-version-check.patch b/patches/server/0309-Improve-java-version-check.patch new file mode 100644 index 0000000000..13df515e7c --- /dev/null +++ b/patches/server/0309-Improve-java-version-check.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Wed, 16 Mar 2022 13:58:16 +0100 +Subject: [PATCH] Improve java version check + +Co-Authored-By: MiniDigger + +diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java +index bb3203dc75df1e480b221fb2de44909759bbf07f..d84afe883d5af0800b5c85649a691bc811c2e357 100644 +--- a/src/main/java/org/bukkit/craftbukkit/Main.java ++++ b/src/main/java/org/bukkit/craftbukkit/Main.java +@@ -203,11 +203,20 @@ public class Main { + return; + } + +- float javaVersion = Float.parseFloat(System.getProperty("java.class.version")); +- if (javaVersion > 67.0) { +- System.err.println("Unsupported Java detected (" + javaVersion + "). Only up to Java 23 is supported."); +- return; ++ // Paper start - Improve java version check ++ boolean skip = Boolean.getBoolean("Paper.IgnoreJavaVersion"); ++ String javaVersionName = System.getProperty("java.version"); ++ // J2SE SDK/JRE Version String Naming Convention ++ boolean isPreRelease = javaVersionName.contains("-"); ++ if (isPreRelease) { ++ if (!skip) { ++ System.err.println("Unsupported Java detected (" + javaVersionName + "). You are running an unsupported, non official, version. Only general availability versions of Java are supported. Please update your Java version. See https://docs.papermc.io/paper/faq#unsupported-java-detected-what-do-i-do for more information."); ++ return; ++ } ++ ++ System.err.println("Unsupported Java detected ("+ javaVersionName + "), but the check was skipped. Proceed with caution! "); + } ++ // Paper end - Improve java version check + + try { + // Paper start - Handled by TerminalConsoleAppender diff --git a/patches/server/0310-Add-ThrownEggHatchEvent.patch b/patches/server/0310-Add-ThrownEggHatchEvent.patch new file mode 100644 index 0000000000..4f5c62f3e6 --- /dev/null +++ b/patches/server/0310-Add-ThrownEggHatchEvent.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 9 Feb 2020 00:19:05 -0600 +Subject: [PATCH] Add ThrownEggHatchEvent + +Adds a new event similar to PlayerEggThrowEvent, but without the Player requirement +(dispensers can throw eggs to hatch them, too). + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java +index eb197a719177dcc1605ee0ff3c471ba91783f040..155c2bbd35adacb7c3668fbe81a7c454e5102c8b 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java +@@ -88,6 +88,13 @@ public class ThrownEgg extends ThrowableItemProjectile { + } + } + // CraftBukkit end ++ // Paper start - Add ThrownEggHatchEvent ++ com.destroystokyo.paper.event.entity.ThrownEggHatchEvent event = new com.destroystokyo.paper.event.entity.ThrownEggHatchEvent((org.bukkit.entity.Egg) getBukkitEntity(), hatching, b0, hatchingType); ++ event.callEvent(); ++ hatching = event.isHatching(); ++ b0 = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0 ++ hatchingType = event.getHatchingType(); ++ // Paper end - Add ThrownEggHatchEvent + + for (int i = 0; i < b0; ++i) { + Entity entitychicken = this.level().getWorld().makeEntity(new org.bukkit.Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F), hatchingType.getEntityClass()); // CraftBukkit diff --git a/patches/server/0310-Improve-java-version-check.patch b/patches/server/0310-Improve-java-version-check.patch deleted file mode 100644 index 13df515e7c..0000000000 --- a/patches/server/0310-Improve-java-version-check.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Wed, 16 Mar 2022 13:58:16 +0100 -Subject: [PATCH] Improve java version check - -Co-Authored-By: MiniDigger - -diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index bb3203dc75df1e480b221fb2de44909759bbf07f..d84afe883d5af0800b5c85649a691bc811c2e357 100644 ---- a/src/main/java/org/bukkit/craftbukkit/Main.java -+++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -203,11 +203,20 @@ public class Main { - return; - } - -- float javaVersion = Float.parseFloat(System.getProperty("java.class.version")); -- if (javaVersion > 67.0) { -- System.err.println("Unsupported Java detected (" + javaVersion + "). Only up to Java 23 is supported."); -- return; -+ // Paper start - Improve java version check -+ boolean skip = Boolean.getBoolean("Paper.IgnoreJavaVersion"); -+ String javaVersionName = System.getProperty("java.version"); -+ // J2SE SDK/JRE Version String Naming Convention -+ boolean isPreRelease = javaVersionName.contains("-"); -+ if (isPreRelease) { -+ if (!skip) { -+ System.err.println("Unsupported Java detected (" + javaVersionName + "). You are running an unsupported, non official, version. Only general availability versions of Java are supported. Please update your Java version. See https://docs.papermc.io/paper/faq#unsupported-java-detected-what-do-i-do for more information."); -+ return; -+ } -+ -+ System.err.println("Unsupported Java detected ("+ javaVersionName + "), but the check was skipped. Proceed with caution! "); - } -+ // Paper end - Improve java version check - - try { - // Paper start - Handled by TerminalConsoleAppender diff --git a/patches/server/0311-Add-ThrownEggHatchEvent.patch b/patches/server/0311-Add-ThrownEggHatchEvent.patch deleted file mode 100644 index 4f5c62f3e6..0000000000 --- a/patches/server/0311-Add-ThrownEggHatchEvent.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 9 Feb 2020 00:19:05 -0600 -Subject: [PATCH] Add ThrownEggHatchEvent - -Adds a new event similar to PlayerEggThrowEvent, but without the Player requirement -(dispensers can throw eggs to hatch them, too). - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java -index eb197a719177dcc1605ee0ff3c471ba91783f040..155c2bbd35adacb7c3668fbe81a7c454e5102c8b 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java -@@ -88,6 +88,13 @@ public class ThrownEgg extends ThrowableItemProjectile { - } - } - // CraftBukkit end -+ // Paper start - Add ThrownEggHatchEvent -+ com.destroystokyo.paper.event.entity.ThrownEggHatchEvent event = new com.destroystokyo.paper.event.entity.ThrownEggHatchEvent((org.bukkit.entity.Egg) getBukkitEntity(), hatching, b0, hatchingType); -+ event.callEvent(); -+ hatching = event.isHatching(); -+ b0 = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0 -+ hatchingType = event.getHatchingType(); -+ // Paper end - Add ThrownEggHatchEvent - - for (int i = 0; i < b0; ++i) { - Entity entitychicken = this.level().getWorld().makeEntity(new org.bukkit.Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F), hatchingType.getEntityClass()); // CraftBukkit diff --git a/patches/server/0311-Entity-Jump-API.patch b/patches/server/0311-Entity-Jump-API.patch new file mode 100644 index 0000000000..8fe49892fd --- /dev/null +++ b/patches/server/0311-Entity-Jump-API.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 8 Feb 2020 23:26:11 -0600 +Subject: [PATCH] Entity Jump API + +== AT == +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 4e6bd9f2e8a1a3b3db8e7fff88eefe88a0f2be65..043d4e85b7021c7bec724c3aef76d1278a7d34d5 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3549,8 +3549,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) { ++ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API + this.jumpFromGround(); + this.noJumpDelay = 10; ++ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop + } + } else { + this.noJumpDelay = 0; +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 0b0887b7d2c69138617bee6ec3145f0a83b8734d..705c26ceff9371b09311bd7fa796c0efde7ebfee 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java +@@ -530,7 +530,9 @@ public class Panda extends Animal { + Panda entitypanda = (Panda) iterator.next(); + + if (!entitypanda.isBaby() && entitypanda.onGround() && !entitypanda.isInWater() && entitypanda.canPerformAction()) { ++ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API + entitypanda.jumpFromGround(); ++ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop + } + } + +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 6c909ea334310f1f9b2d9a2e2cc2f23f2badba37..772476d44ee72aed1ba35d10fe51f0ffda34d3f8 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java +@@ -171,7 +171,9 @@ public class Ravager extends Raider { + } + + if (!flag && this.onGround()) { ++ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API + this.jumpFromGround(); ++ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop + } + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index db21f7eeeca48f1df95b37ffa7e9bf7f71f37d5d..c763d3524794a2505a6296917d34b6f7e737402d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -993,4 +993,20 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + return org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(this.getHandle().getUsedItemHand()); + } + // Paper end - active item API ++ ++ // Paper start - entity jump API ++ @Override ++ public boolean isJumping() { ++ return getHandle().jumping; ++ } ++ ++ @Override ++ public void setJumping(boolean jumping) { ++ getHandle().setJumping(jumping); ++ if (jumping && getHandle() instanceof Mob) { ++ // this is needed to actually make a mob jump ++ ((Mob) getHandle()).getJumpControl().jump(); ++ } ++ } ++ // Paper end - entity jump API + } diff --git a/patches/server/0312-Add-option-to-nerf-pigmen-from-nether-portals.patch b/patches/server/0312-Add-option-to-nerf-pigmen-from-nether-portals.patch new file mode 100644 index 0000000000..155da7f04a --- /dev/null +++ b/patches/server/0312-Add-option-to-nerf-pigmen-from-nether-portals.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 7 Feb 2020 14:36:56 -0600 +Subject: [PATCH] Add option to nerf pigmen from nether portals + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 2179f631bf410297db2438e587f4b5ecb7ebc218..dcc6543f895c9bbf09301e64164873aa54c7b8b5 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -407,6 +407,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public void inactiveTick() { } + // Spigot end + protected int numCollisions = 0; // Paper - Cap entity collisions ++ public boolean fromNetherPortal; // Paper - Add option to nerf pigmen from nether portals + public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one + // Paper start - Entity origin API + @javax.annotation.Nullable +@@ -2422,6 +2423,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + if (spawnedViaMobSpawner) { + nbttagcompound.putBoolean("Paper.FromMobSpawner", true); + } ++ if (fromNetherPortal) { ++ nbttagcompound.putBoolean("Paper.FromNetherPortal", true); ++ } + // Paper end + return nbttagcompound; + } catch (Throwable throwable) { +@@ -2567,6 +2571,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status ++ fromNetherPortal = nbt.getBoolean("Paper.FromNetherPortal"); + if (nbt.contains("Paper.SpawnReason")) { + String spawnReasonName = nbt.getString("Paper.SpawnReason"); + try { +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 a8cb0d5019d06de64b2cc30e6830bbd6ad43a155..e404722c119631e31c0519111ccd5f1682c2638d 100644 +--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +@@ -89,6 +89,10 @@ public class NetherPortalBlock extends Block implements Portal { + + if (entity != null) { + entity.setPortalCooldown(); ++ // Paper start - Add option to nerf pigmen from nether portals ++ entity.fromNetherPortal = true; ++ if (world.paperConfig().entities.behavior.nerfPigmenFromNetherPortals) ((net.minecraft.world.entity.Mob) entity).aware = false; ++ // Paper end - Add option to nerf pigmen from nether portals + Entity entity1 = entity.getVehicle(); + + if (entity1 != null) { diff --git a/patches/server/0312-Entity-Jump-API.patch b/patches/server/0312-Entity-Jump-API.patch deleted file mode 100644 index 8fe49892fd..0000000000 --- a/patches/server/0312-Entity-Jump-API.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 8 Feb 2020 23:26:11 -0600 -Subject: [PATCH] Entity Jump API - -== AT == -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 4e6bd9f2e8a1a3b3db8e7fff88eefe88a0f2be65..043d4e85b7021c7bec724c3aef76d1278a7d34d5 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3549,8 +3549,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) { -+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API - this.jumpFromGround(); - this.noJumpDelay = 10; -+ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop - } - } else { - this.noJumpDelay = 0; -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 0b0887b7d2c69138617bee6ec3145f0a83b8734d..705c26ceff9371b09311bd7fa796c0efde7ebfee 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Panda.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java -@@ -530,7 +530,9 @@ public class Panda extends Animal { - Panda entitypanda = (Panda) iterator.next(); - - if (!entitypanda.isBaby() && entitypanda.onGround() && !entitypanda.isInWater() && entitypanda.canPerformAction()) { -+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API - entitypanda.jumpFromGround(); -+ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop - } - } - -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 6c909ea334310f1f9b2d9a2e2cc2f23f2badba37..772476d44ee72aed1ba35d10fe51f0ffda34d3f8 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -171,7 +171,9 @@ public class Ravager extends Raider { - } - - if (!flag && this.onGround()) { -+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API - this.jumpFromGround(); -+ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop - } - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index db21f7eeeca48f1df95b37ffa7e9bf7f71f37d5d..c763d3524794a2505a6296917d34b6f7e737402d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -993,4 +993,20 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - return org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(this.getHandle().getUsedItemHand()); - } - // Paper end - active item API -+ -+ // Paper start - entity jump API -+ @Override -+ public boolean isJumping() { -+ return getHandle().jumping; -+ } -+ -+ @Override -+ public void setJumping(boolean jumping) { -+ getHandle().setJumping(jumping); -+ if (jumping && getHandle() instanceof Mob) { -+ // this is needed to actually make a mob jump -+ ((Mob) getHandle()).getJumpControl().jump(); -+ } -+ } -+ // Paper end - entity jump API - } diff --git a/patches/server/0313-Add-option-to-nerf-pigmen-from-nether-portals.patch b/patches/server/0313-Add-option-to-nerf-pigmen-from-nether-portals.patch deleted file mode 100644 index 2bbd5a37f8..0000000000 --- a/patches/server/0313-Add-option-to-nerf-pigmen-from-nether-portals.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 7 Feb 2020 14:36:56 -0600 -Subject: [PATCH] Add option to nerf pigmen from nether portals - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index e932bd4c922d7015bba0ef06e349d74f5c1a209c..a330a603349f7f9d694cef66f67ba465e3110a1c 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -407,6 +407,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public void inactiveTick() { } - // Spigot end - protected int numCollisions = 0; // Paper - Cap entity collisions -+ public boolean fromNetherPortal; // Paper - Add option to nerf pigmen from nether portals - public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one - // Paper start - Entity origin API - @javax.annotation.Nullable -@@ -2422,6 +2423,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (spawnedViaMobSpawner) { - nbttagcompound.putBoolean("Paper.FromMobSpawner", true); - } -+ if (fromNetherPortal) { -+ nbttagcompound.putBoolean("Paper.FromNetherPortal", true); -+ } - // Paper end - return nbttagcompound; - } catch (Throwable throwable) { -@@ -2567,6 +2571,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status -+ fromNetherPortal = nbt.getBoolean("Paper.FromNetherPortal"); - if (nbt.contains("Paper.SpawnReason")) { - String spawnReasonName = nbt.getString("Paper.SpawnReason"); - try { -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 a8cb0d5019d06de64b2cc30e6830bbd6ad43a155..e404722c119631e31c0519111ccd5f1682c2638d 100644 ---- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -@@ -89,6 +89,10 @@ public class NetherPortalBlock extends Block implements Portal { - - if (entity != null) { - entity.setPortalCooldown(); -+ // Paper start - Add option to nerf pigmen from nether portals -+ entity.fromNetherPortal = true; -+ if (world.paperConfig().entities.behavior.nerfPigmenFromNetherPortals) ((net.minecraft.world.entity.Mob) entity).aware = false; -+ // Paper end - Add option to nerf pigmen from nether portals - Entity entity1 = entity.getVehicle(); - - if (entity1 != null) { diff --git a/patches/server/0313-Make-the-GUI-graph-fancier.patch b/patches/server/0313-Make-the-GUI-graph-fancier.patch new file mode 100644 index 0000000000..25e1012aa6 --- /dev/null +++ b/patches/server/0313-Make-the-GUI-graph-fancier.patch @@ -0,0 +1,411 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 2 Feb 2020 04:00:40 -0600 +Subject: [PATCH] Make the GUI graph fancier + + +diff --git a/src/main/java/com/destroystokyo/paper/gui/GraphColor.java b/src/main/java/com/destroystokyo/paper/gui/GraphColor.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a4e641fdcccd3efcd1a2865dc6dc28d50671b995 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/gui/GraphColor.java +@@ -0,0 +1,44 @@ ++package com.destroystokyo.paper.gui; ++ ++import java.awt.Color; ++ ++public class GraphColor { ++ private static final Color[] colorLine = new Color[101]; ++ private static final Color[] colorFill = new Color[101]; ++ ++ static { ++ for (int i = 0; i < 101; i++) { ++ Color color = createColor(i); ++ colorLine[i] = new Color(color.getRed() / 2, color.getGreen() / 2, color.getBlue() / 2, 255); ++ colorFill[i] = new Color(colorLine[i].getRed(), colorLine[i].getGreen(), colorLine[i].getBlue(), 125); ++ } ++ } ++ ++ public static Color getLineColor(int percent) { ++ return colorLine[percent]; ++ } ++ ++ public static Color getFillColor(int percent) { ++ return colorFill[percent]; ++ } ++ ++ private static Color createColor(int percent) { ++ if (percent <= 50) { ++ return new Color(0X00FF00); ++ } ++ ++ int value = 510 - (int) (Math.min(Math.max(0, ((percent - 50) / 50F)), 1) * 510); ++ ++ int red, green; ++ if (value < 255) { ++ red = 255; ++ green = (int) (Math.sqrt(value) * 16); ++ } else { ++ green = 255; ++ value = value - 255; ++ red = 255 - (value * value / 255); ++ } ++ ++ return new Color(red, green, 0); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/gui/GraphData.java b/src/main/java/com/destroystokyo/paper/gui/GraphData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..186fc722965e403f76b1480e1c2381fc34e29049 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/gui/GraphData.java +@@ -0,0 +1,47 @@ ++package com.destroystokyo.paper.gui; ++ ++import java.awt.Color; ++ ++public class GraphData { ++ private long total; ++ private long free; ++ private long max; ++ private long usedMem; ++ private int usedPercent; ++ ++ public GraphData(long total, long free, long max) { ++ this.total = total; ++ this.free = free; ++ this.max = max; ++ this.usedMem = total - free; ++ this.usedPercent = usedMem == 0 ? 0 : (int) (usedMem * 100L / max); ++ } ++ ++ public long getTotal() { ++ return total; ++ } ++ ++ public long getFree() { ++ return free; ++ } ++ ++ public long getMax() { ++ return max; ++ } ++ ++ public long getUsedMem() { ++ return usedMem; ++ } ++ ++ public int getUsedPercent() { ++ return usedPercent; ++ } ++ ++ public Color getFillColor() { ++ return GraphColor.getFillColor(usedPercent); ++ } ++ ++ public Color getLineColor() { ++ return GraphColor.getLineColor(usedPercent); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..537bc6213545e8ff1b7b51bc4b27fd5b2a740883 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java +@@ -0,0 +1,41 @@ ++package com.destroystokyo.paper.gui; ++ ++import net.minecraft.server.MinecraftServer; ++ ++import javax.swing.JPanel; ++import javax.swing.Timer; ++import java.awt.BorderLayout; ++import java.awt.Dimension; ++ ++public class GuiStatsComponent extends JPanel { ++ private final Timer timer; ++ private final RAMGraph ramGraph; ++ ++ public GuiStatsComponent(MinecraftServer server) { ++ super(new BorderLayout()); ++ ++ setOpaque(false); ++ ++ ramGraph = new RAMGraph(); ++ RAMDetails ramDetails = new RAMDetails(server); ++ ++ add(ramGraph, "North"); ++ add(ramDetails, "Center"); ++ ++ timer = new Timer(500, (event) -> { ++ ramGraph.update(); ++ ramDetails.update(); ++ }); ++ timer.start(); ++ } ++ ++ @Override ++ public Dimension getPreferredSize() { ++ return new Dimension(350, 200); ++ } ++ ++ public void close() { ++ timer.stop(); ++ ramGraph.stop(); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f93373d28d741e1f8a53e07b4e328ce9c4e1657f +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java +@@ -0,0 +1,74 @@ ++package com.destroystokyo.paper.gui; ++ ++import net.minecraft.Util; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.util.TimeUtil; ++ ++import javax.swing.DefaultListCellRenderer; ++import javax.swing.DefaultListSelectionModel; ++import javax.swing.JList; ++import javax.swing.border.EmptyBorder; ++import java.awt.Dimension; ++import java.text.DecimalFormat; ++import java.text.DecimalFormatSymbols; ++import java.util.Locale; ++import java.util.Vector; ++ ++public class RAMDetails extends JList { ++ public static final DecimalFormat DECIMAL_FORMAT = Util.make(new DecimalFormat("########0.000"), (format) ++ -> format.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT))); ++ ++ private final MinecraftServer server; ++ ++ public RAMDetails(MinecraftServer server) { ++ this.server = server; ++ ++ setBorder(new EmptyBorder(0, 10, 0, 0)); ++ setFixedCellHeight(20); ++ setOpaque(false); ++ ++ DefaultListCellRenderer renderer = new DefaultListCellRenderer(); ++ renderer.setOpaque(false); ++ setCellRenderer(renderer); ++ ++ setSelectionModel(new DefaultListSelectionModel() { ++ @Override ++ public void setAnchorSelectionIndex(final int anchorIndex) { ++ } ++ ++ @Override ++ public void setLeadAnchorNotificationEnabled(final boolean flag) { ++ } ++ ++ @Override ++ public void setLeadSelectionIndex(final int leadIndex) { ++ } ++ ++ @Override ++ public void setSelectionInterval(final int index0, final int index1) { ++ } ++ }); ++ } ++ ++ @Override ++ public Dimension getPreferredSize() { ++ return new Dimension(350, 100); ++ } ++ ++ public void update() { ++ GraphData data = RAMGraph.DATA.peekLast(); ++ Vector vector = new Vector<>(); ++ vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)"); ++ vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb"); ++ vector.add("Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms"); ++ setListData(vector); ++ } ++ ++ public double getAverage(long[] tickTimes) { ++ long total = 0L; ++ for (long value : tickTimes) { ++ total += value * 1000; ++ } ++ return ((double) total / (double) tickTimes.length) * 1.0E-6D; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java b/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a844669c57290cbdf66245d91fc9d2fbf23ba947 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java +@@ -0,0 +1,156 @@ ++package com.destroystokyo.paper.gui; ++ ++import javax.swing.JComponent; ++import javax.swing.SwingUtilities; ++import javax.swing.Timer; ++import javax.swing.ToolTipManager; ++import java.awt.Color; ++import java.awt.Dimension; ++import java.awt.Graphics; ++import java.awt.MouseInfo; ++import java.awt.Point; ++import java.awt.PointerInfo; ++import java.awt.event.MouseAdapter; ++import java.awt.event.MouseEvent; ++import java.text.SimpleDateFormat; ++import java.util.Date; ++import java.util.LinkedList; ++import java.util.concurrent.TimeUnit; ++ ++public class RAMGraph extends JComponent { ++ public static final LinkedList DATA = new LinkedList() { ++ @Override ++ public boolean add(GraphData data) { ++ if (size() >= 348) { ++ remove(); ++ } ++ return super.add(data); ++ } ++ }; ++ ++ static { ++ GraphData empty = new GraphData(0, 0, 0); ++ for (int i = 0; i < 350; i++) { ++ DATA.add(empty); ++ } ++ } ++ ++ private final Timer timer; ++ private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss"); ++ ++ private int currentTick; ++ ++ public RAMGraph() { ++ ToolTipManager.sharedInstance().setInitialDelay(0); ++ ++ addMouseListener(new MouseAdapter() { ++ final int defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay(); ++ final int dismissDelayMinutes = (int) TimeUnit.MINUTES.toMillis(10); ++ ++ @Override ++ public void mouseEntered(MouseEvent me) { ++ ToolTipManager.sharedInstance().setDismissDelay(dismissDelayMinutes); ++ } ++ ++ @Override ++ public void mouseExited(MouseEvent me) { ++ ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout); ++ } ++ }); ++ ++ timer = new Timer(50, (event) -> repaint()); ++ timer.start(); ++ } ++ ++ @Override ++ public Dimension getPreferredSize() { ++ return new Dimension(350, 110); ++ } ++ ++ public void update() { ++ Runtime jvm = Runtime.getRuntime(); ++ DATA.add(new GraphData(jvm.totalMemory(), jvm.freeMemory(), jvm.maxMemory())); ++ ++ PointerInfo pointerInfo = null; ++ // I think I recall spotting a bug report where this throwed an exception once ++ // not sure it's of concern here ++ try { ++ pointerInfo = MouseInfo.getPointerInfo(); ++ } catch (NullPointerException | ArrayIndexOutOfBoundsException ignored) { ++ // https://bugs.openjdk.org/browse/JDK-6840067 ++ } ++ if (pointerInfo != null) { ++ Point point = pointerInfo.getLocation(); ++ if (point != null) { ++ Point loc = new Point(point); ++ SwingUtilities.convertPointFromScreen(loc, this); ++ if (this.contains(loc)) { ++ ToolTipManager.sharedInstance().mouseMoved( ++ new MouseEvent(this, -1, System.currentTimeMillis(), 0, loc.x, loc.y, ++ point.x, point.y, 0, false, 0)); ++ } ++ } ++ } ++ ++ currentTick++; ++ } ++ ++ @Override ++ public void paint(Graphics graphics) { ++ graphics.setColor(new Color(0xFFFFFFFF)); ++ graphics.fillRect(0, 0, 350, 100); ++ ++ graphics.setColor(new Color(0x888888)); ++ graphics.drawLine(1, 25, 348, 25); ++ graphics.drawLine(1, 50, 348, 50); ++ graphics.drawLine(1, 75, 348, 75); ++ ++ int i = 0; ++ for (GraphData data : DATA) { ++ i++; ++ if ((i + currentTick) % 120 == 0) { ++ graphics.setColor(new Color(0x888888)); ++ graphics.drawLine(i, 1, i, 99); ++ } ++ int used = data.getUsedPercent(); ++ if (used > 0) { ++ Color color = data.getLineColor(); ++ graphics.setColor(data.getFillColor()); ++ graphics.fillRect(i, 100 - used, 1, used); ++ graphics.setColor(color); ++ graphics.fillRect(i, 100 - used, 1, 1); ++ } ++ } ++ ++ graphics.setColor(new Color(0xFF000000)); ++ graphics.drawRect(0, 0, 348, 100); ++ ++ Point m = null; ++ try { ++ m = getMousePosition(); ++ } catch (NullPointerException ignored) { ++ // https://bugs.openjdk.org/browse/JDK-6840067 ++ } ++ if (m != null && m.x > 0 && m.x < 348 && m.y > 0 && m.y < 100) { ++ GraphData data = DATA.get(m.x); ++ int used = data.getUsedPercent(); ++ graphics.setColor(new Color(0x000000)); ++ graphics.drawLine(m.x, 1, m.x, 99); ++ graphics.drawOval(m.x - 2, 100 - used - 2, 5, 5); ++ graphics.setColor(data.getLineColor()); ++ graphics.fillOval(m.x - 2, 100 - used - 2, 5, 5); ++ setToolTipText(String.format("Used: %s mb (%s%%)
%s", ++ Math.round(data.getUsedMem() / 1024F / 1024F), ++ used, getTime(m.x))); ++ } ++ } ++ ++ public String getTime(int halfSeconds) { ++ int millis = (348 - halfSeconds) / 2 * 1000; ++ return TIME_FORMAT.format(new Date((System.currentTimeMillis() - millis))); ++ } ++ ++ public void stop() { ++ timer.stop(); ++ } ++} +diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java +index 84a2c6c397604279ba821286f5c3c855e6041400..8b570b0c3967a22c085f390110cb29cbd9c8feff 100644 +--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java ++++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java +@@ -95,7 +95,7 @@ public class MinecraftServerGui extends JComponent { + + private JComponent buildInfoPanel() { + JPanel jpanel = new JPanel(new BorderLayout()); +- StatsComponent guistatscomponent = new StatsComponent(this.server); ++ com.destroystokyo.paper.gui.GuiStatsComponent guistatscomponent = new com.destroystokyo.paper.gui.GuiStatsComponent(this.server); // Paper - Make GUI graph fancier + Collection collection = this.finalizers; // CraftBukkit - decompile error + + Objects.requireNonNull(guistatscomponent); diff --git a/patches/server/0314-Make-the-GUI-graph-fancier.patch b/patches/server/0314-Make-the-GUI-graph-fancier.patch deleted file mode 100644 index 25e1012aa6..0000000000 --- a/patches/server/0314-Make-the-GUI-graph-fancier.patch +++ /dev/null @@ -1,411 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 2 Feb 2020 04:00:40 -0600 -Subject: [PATCH] Make the GUI graph fancier - - -diff --git a/src/main/java/com/destroystokyo/paper/gui/GraphColor.java b/src/main/java/com/destroystokyo/paper/gui/GraphColor.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a4e641fdcccd3efcd1a2865dc6dc28d50671b995 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/gui/GraphColor.java -@@ -0,0 +1,44 @@ -+package com.destroystokyo.paper.gui; -+ -+import java.awt.Color; -+ -+public class GraphColor { -+ private static final Color[] colorLine = new Color[101]; -+ private static final Color[] colorFill = new Color[101]; -+ -+ static { -+ for (int i = 0; i < 101; i++) { -+ Color color = createColor(i); -+ colorLine[i] = new Color(color.getRed() / 2, color.getGreen() / 2, color.getBlue() / 2, 255); -+ colorFill[i] = new Color(colorLine[i].getRed(), colorLine[i].getGreen(), colorLine[i].getBlue(), 125); -+ } -+ } -+ -+ public static Color getLineColor(int percent) { -+ return colorLine[percent]; -+ } -+ -+ public static Color getFillColor(int percent) { -+ return colorFill[percent]; -+ } -+ -+ private static Color createColor(int percent) { -+ if (percent <= 50) { -+ return new Color(0X00FF00); -+ } -+ -+ int value = 510 - (int) (Math.min(Math.max(0, ((percent - 50) / 50F)), 1) * 510); -+ -+ int red, green; -+ if (value < 255) { -+ red = 255; -+ green = (int) (Math.sqrt(value) * 16); -+ } else { -+ green = 255; -+ value = value - 255; -+ red = 255 - (value * value / 255); -+ } -+ -+ return new Color(red, green, 0); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/gui/GraphData.java b/src/main/java/com/destroystokyo/paper/gui/GraphData.java -new file mode 100644 -index 0000000000000000000000000000000000000000..186fc722965e403f76b1480e1c2381fc34e29049 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/gui/GraphData.java -@@ -0,0 +1,47 @@ -+package com.destroystokyo.paper.gui; -+ -+import java.awt.Color; -+ -+public class GraphData { -+ private long total; -+ private long free; -+ private long max; -+ private long usedMem; -+ private int usedPercent; -+ -+ public GraphData(long total, long free, long max) { -+ this.total = total; -+ this.free = free; -+ this.max = max; -+ this.usedMem = total - free; -+ this.usedPercent = usedMem == 0 ? 0 : (int) (usedMem * 100L / max); -+ } -+ -+ public long getTotal() { -+ return total; -+ } -+ -+ public long getFree() { -+ return free; -+ } -+ -+ public long getMax() { -+ return max; -+ } -+ -+ public long getUsedMem() { -+ return usedMem; -+ } -+ -+ public int getUsedPercent() { -+ return usedPercent; -+ } -+ -+ public Color getFillColor() { -+ return GraphColor.getFillColor(usedPercent); -+ } -+ -+ public Color getLineColor() { -+ return GraphColor.getLineColor(usedPercent); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..537bc6213545e8ff1b7b51bc4b27fd5b2a740883 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java -@@ -0,0 +1,41 @@ -+package com.destroystokyo.paper.gui; -+ -+import net.minecraft.server.MinecraftServer; -+ -+import javax.swing.JPanel; -+import javax.swing.Timer; -+import java.awt.BorderLayout; -+import java.awt.Dimension; -+ -+public class GuiStatsComponent extends JPanel { -+ private final Timer timer; -+ private final RAMGraph ramGraph; -+ -+ public GuiStatsComponent(MinecraftServer server) { -+ super(new BorderLayout()); -+ -+ setOpaque(false); -+ -+ ramGraph = new RAMGraph(); -+ RAMDetails ramDetails = new RAMDetails(server); -+ -+ add(ramGraph, "North"); -+ add(ramDetails, "Center"); -+ -+ timer = new Timer(500, (event) -> { -+ ramGraph.update(); -+ ramDetails.update(); -+ }); -+ timer.start(); -+ } -+ -+ @Override -+ public Dimension getPreferredSize() { -+ return new Dimension(350, 200); -+ } -+ -+ public void close() { -+ timer.stop(); -+ ramGraph.stop(); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f93373d28d741e1f8a53e07b4e328ce9c4e1657f ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java -@@ -0,0 +1,74 @@ -+package com.destroystokyo.paper.gui; -+ -+import net.minecraft.Util; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.util.TimeUtil; -+ -+import javax.swing.DefaultListCellRenderer; -+import javax.swing.DefaultListSelectionModel; -+import javax.swing.JList; -+import javax.swing.border.EmptyBorder; -+import java.awt.Dimension; -+import java.text.DecimalFormat; -+import java.text.DecimalFormatSymbols; -+import java.util.Locale; -+import java.util.Vector; -+ -+public class RAMDetails extends JList { -+ public static final DecimalFormat DECIMAL_FORMAT = Util.make(new DecimalFormat("########0.000"), (format) -+ -> format.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT))); -+ -+ private final MinecraftServer server; -+ -+ public RAMDetails(MinecraftServer server) { -+ this.server = server; -+ -+ setBorder(new EmptyBorder(0, 10, 0, 0)); -+ setFixedCellHeight(20); -+ setOpaque(false); -+ -+ DefaultListCellRenderer renderer = new DefaultListCellRenderer(); -+ renderer.setOpaque(false); -+ setCellRenderer(renderer); -+ -+ setSelectionModel(new DefaultListSelectionModel() { -+ @Override -+ public void setAnchorSelectionIndex(final int anchorIndex) { -+ } -+ -+ @Override -+ public void setLeadAnchorNotificationEnabled(final boolean flag) { -+ } -+ -+ @Override -+ public void setLeadSelectionIndex(final int leadIndex) { -+ } -+ -+ @Override -+ public void setSelectionInterval(final int index0, final int index1) { -+ } -+ }); -+ } -+ -+ @Override -+ public Dimension getPreferredSize() { -+ return new Dimension(350, 100); -+ } -+ -+ public void update() { -+ GraphData data = RAMGraph.DATA.peekLast(); -+ Vector vector = new Vector<>(); -+ vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)"); -+ vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb"); -+ vector.add("Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms"); -+ setListData(vector); -+ } -+ -+ public double getAverage(long[] tickTimes) { -+ long total = 0L; -+ for (long value : tickTimes) { -+ total += value * 1000; -+ } -+ return ((double) total / (double) tickTimes.length) * 1.0E-6D; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java b/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a844669c57290cbdf66245d91fc9d2fbf23ba947 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/gui/RAMGraph.java -@@ -0,0 +1,156 @@ -+package com.destroystokyo.paper.gui; -+ -+import javax.swing.JComponent; -+import javax.swing.SwingUtilities; -+import javax.swing.Timer; -+import javax.swing.ToolTipManager; -+import java.awt.Color; -+import java.awt.Dimension; -+import java.awt.Graphics; -+import java.awt.MouseInfo; -+import java.awt.Point; -+import java.awt.PointerInfo; -+import java.awt.event.MouseAdapter; -+import java.awt.event.MouseEvent; -+import java.text.SimpleDateFormat; -+import java.util.Date; -+import java.util.LinkedList; -+import java.util.concurrent.TimeUnit; -+ -+public class RAMGraph extends JComponent { -+ public static final LinkedList DATA = new LinkedList() { -+ @Override -+ public boolean add(GraphData data) { -+ if (size() >= 348) { -+ remove(); -+ } -+ return super.add(data); -+ } -+ }; -+ -+ static { -+ GraphData empty = new GraphData(0, 0, 0); -+ for (int i = 0; i < 350; i++) { -+ DATA.add(empty); -+ } -+ } -+ -+ private final Timer timer; -+ private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss"); -+ -+ private int currentTick; -+ -+ public RAMGraph() { -+ ToolTipManager.sharedInstance().setInitialDelay(0); -+ -+ addMouseListener(new MouseAdapter() { -+ final int defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay(); -+ final int dismissDelayMinutes = (int) TimeUnit.MINUTES.toMillis(10); -+ -+ @Override -+ public void mouseEntered(MouseEvent me) { -+ ToolTipManager.sharedInstance().setDismissDelay(dismissDelayMinutes); -+ } -+ -+ @Override -+ public void mouseExited(MouseEvent me) { -+ ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout); -+ } -+ }); -+ -+ timer = new Timer(50, (event) -> repaint()); -+ timer.start(); -+ } -+ -+ @Override -+ public Dimension getPreferredSize() { -+ return new Dimension(350, 110); -+ } -+ -+ public void update() { -+ Runtime jvm = Runtime.getRuntime(); -+ DATA.add(new GraphData(jvm.totalMemory(), jvm.freeMemory(), jvm.maxMemory())); -+ -+ PointerInfo pointerInfo = null; -+ // I think I recall spotting a bug report where this throwed an exception once -+ // not sure it's of concern here -+ try { -+ pointerInfo = MouseInfo.getPointerInfo(); -+ } catch (NullPointerException | ArrayIndexOutOfBoundsException ignored) { -+ // https://bugs.openjdk.org/browse/JDK-6840067 -+ } -+ if (pointerInfo != null) { -+ Point point = pointerInfo.getLocation(); -+ if (point != null) { -+ Point loc = new Point(point); -+ SwingUtilities.convertPointFromScreen(loc, this); -+ if (this.contains(loc)) { -+ ToolTipManager.sharedInstance().mouseMoved( -+ new MouseEvent(this, -1, System.currentTimeMillis(), 0, loc.x, loc.y, -+ point.x, point.y, 0, false, 0)); -+ } -+ } -+ } -+ -+ currentTick++; -+ } -+ -+ @Override -+ public void paint(Graphics graphics) { -+ graphics.setColor(new Color(0xFFFFFFFF)); -+ graphics.fillRect(0, 0, 350, 100); -+ -+ graphics.setColor(new Color(0x888888)); -+ graphics.drawLine(1, 25, 348, 25); -+ graphics.drawLine(1, 50, 348, 50); -+ graphics.drawLine(1, 75, 348, 75); -+ -+ int i = 0; -+ for (GraphData data : DATA) { -+ i++; -+ if ((i + currentTick) % 120 == 0) { -+ graphics.setColor(new Color(0x888888)); -+ graphics.drawLine(i, 1, i, 99); -+ } -+ int used = data.getUsedPercent(); -+ if (used > 0) { -+ Color color = data.getLineColor(); -+ graphics.setColor(data.getFillColor()); -+ graphics.fillRect(i, 100 - used, 1, used); -+ graphics.setColor(color); -+ graphics.fillRect(i, 100 - used, 1, 1); -+ } -+ } -+ -+ graphics.setColor(new Color(0xFF000000)); -+ graphics.drawRect(0, 0, 348, 100); -+ -+ Point m = null; -+ try { -+ m = getMousePosition(); -+ } catch (NullPointerException ignored) { -+ // https://bugs.openjdk.org/browse/JDK-6840067 -+ } -+ if (m != null && m.x > 0 && m.x < 348 && m.y > 0 && m.y < 100) { -+ GraphData data = DATA.get(m.x); -+ int used = data.getUsedPercent(); -+ graphics.setColor(new Color(0x000000)); -+ graphics.drawLine(m.x, 1, m.x, 99); -+ graphics.drawOval(m.x - 2, 100 - used - 2, 5, 5); -+ graphics.setColor(data.getLineColor()); -+ graphics.fillOval(m.x - 2, 100 - used - 2, 5, 5); -+ setToolTipText(String.format("Used: %s mb (%s%%)
%s", -+ Math.round(data.getUsedMem() / 1024F / 1024F), -+ used, getTime(m.x))); -+ } -+ } -+ -+ public String getTime(int halfSeconds) { -+ int millis = (348 - halfSeconds) / 2 * 1000; -+ return TIME_FORMAT.format(new Date((System.currentTimeMillis() - millis))); -+ } -+ -+ public void stop() { -+ timer.stop(); -+ } -+} -diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java -index 84a2c6c397604279ba821286f5c3c855e6041400..8b570b0c3967a22c085f390110cb29cbd9c8feff 100644 ---- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java -+++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java -@@ -95,7 +95,7 @@ public class MinecraftServerGui extends JComponent { - - private JComponent buildInfoPanel() { - JPanel jpanel = new JPanel(new BorderLayout()); -- StatsComponent guistatscomponent = new StatsComponent(this.server); -+ com.destroystokyo.paper.gui.GuiStatsComponent guistatscomponent = new com.destroystokyo.paper.gui.GuiStatsComponent(this.server); // Paper - Make GUI graph fancier - Collection collection = this.finalizers; // CraftBukkit - decompile error - - Objects.requireNonNull(guistatscomponent); diff --git a/patches/server/0314-add-hand-to-BlockMultiPlaceEvent.patch b/patches/server/0314-add-hand-to-BlockMultiPlaceEvent.patch new file mode 100644 index 0000000000..b9b59dc0c9 --- /dev/null +++ b/patches/server/0314-add-hand-to-BlockMultiPlaceEvent.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Trigary +Date: Sun, 1 Mar 2020 22:43:24 +0100 +Subject: [PATCH] add hand to BlockMultiPlaceEvent + + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index b537b3ac2ed238c01ec76ccc7941a09bfc959c10..74f33aeb6193080446ebbcc5242d95c3b1c97823 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -411,13 +411,18 @@ public class CraftEventFactory { + } + + org.bukkit.inventory.ItemStack item; ++ // Paper start - add hand to BlockMultiPlaceEvent ++ EquipmentSlot equipmentSlot; + if (hand == InteractionHand.MAIN_HAND) { + item = player.getInventory().getItemInMainHand(); ++ equipmentSlot = EquipmentSlot.HAND; + } else { + item = player.getInventory().getItemInOffHand(); ++ equipmentSlot = EquipmentSlot.OFF_HAND; + } + +- BlockMultiPlaceEvent event = new BlockMultiPlaceEvent(blockStates, blockClicked, item, player, canBuild); ++ BlockMultiPlaceEvent event = new BlockMultiPlaceEvent(blockStates, blockClicked, item, player, canBuild, equipmentSlot); ++ // Paper end + craftServer.getPluginManager().callEvent(event); + + return event; diff --git a/patches/server/0315-Validate-tripwire-hook-placement-before-update.patch b/patches/server/0315-Validate-tripwire-hook-placement-before-update.patch new file mode 100644 index 0000000000..b607c1afe9 --- /dev/null +++ b/patches/server/0315-Validate-tripwire-hook-placement-before-update.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sat, 7 Mar 2020 00:07:51 +0000 +Subject: [PATCH] Validate tripwire hook placement before update + + +diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java +index 1240f18b3d40f8bde2346c893304ae340a727e24..c2589f42c467ca672417c24076313da51bb2dcbb 100644 +--- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java +@@ -191,6 +191,7 @@ public class TripWireHookBlock extends Block { + + TripWireHookBlock.emitState(world, pos, flag4, flag5, flag2, flag3); + if (!flag) { ++ if (world.getBlockState(pos).getBlock() == Blocks.TRIPWIRE_HOOK) // Paper - Validate tripwire hook placement before update + world.setBlock(pos, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection), 3); + if (flag1) { + TripWireHookBlock.notifyNeighbors(block, world, pos, enumdirection); diff --git a/patches/server/0315-add-hand-to-BlockMultiPlaceEvent.patch b/patches/server/0315-add-hand-to-BlockMultiPlaceEvent.patch deleted file mode 100644 index b9b59dc0c9..0000000000 --- a/patches/server/0315-add-hand-to-BlockMultiPlaceEvent.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trigary -Date: Sun, 1 Mar 2020 22:43:24 +0100 -Subject: [PATCH] add hand to BlockMultiPlaceEvent - - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index b537b3ac2ed238c01ec76ccc7941a09bfc959c10..74f33aeb6193080446ebbcc5242d95c3b1c97823 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -411,13 +411,18 @@ public class CraftEventFactory { - } - - org.bukkit.inventory.ItemStack item; -+ // Paper start - add hand to BlockMultiPlaceEvent -+ EquipmentSlot equipmentSlot; - if (hand == InteractionHand.MAIN_HAND) { - item = player.getInventory().getItemInMainHand(); -+ equipmentSlot = EquipmentSlot.HAND; - } else { - item = player.getInventory().getItemInOffHand(); -+ equipmentSlot = EquipmentSlot.OFF_HAND; - } - -- BlockMultiPlaceEvent event = new BlockMultiPlaceEvent(blockStates, blockClicked, item, player, canBuild); -+ BlockMultiPlaceEvent event = new BlockMultiPlaceEvent(blockStates, blockClicked, item, player, canBuild, equipmentSlot); -+ // Paper end - craftServer.getPluginManager().callEvent(event); - - return event; diff --git a/patches/server/0316-Add-option-to-allow-iron-golems-to-spawn-in-air.patch b/patches/server/0316-Add-option-to-allow-iron-golems-to-spawn-in-air.patch new file mode 100644 index 0000000000..8991de1b70 --- /dev/null +++ b/patches/server/0316-Add-option-to-allow-iron-golems-to-spawn-in-air.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 13 Apr 2019 16:50:58 -0500 +Subject: [PATCH] Add option to allow iron golems to spawn in air + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java +index dac63f51fc23cc7f35ee299d1e04c96c210db52b..e07b79ef172095c1800c88342b3ac8dc7703aea2 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java ++++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java +@@ -319,7 +319,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + BlockPos blockposition1 = blockposition.below(); + BlockState iblockdata = world.getBlockState(blockposition1); + +- if (!iblockdata.entityCanStandOn(world, blockposition1, this)) { ++ if (!iblockdata.entityCanStandOn(world, blockposition1, this) && !this.level().paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper - Add option to allow iron golems to spawn in air + return false; + } else { + for (int i = 1; i < 3; ++i) { diff --git a/patches/server/0316-Validate-tripwire-hook-placement-before-update.patch b/patches/server/0316-Validate-tripwire-hook-placement-before-update.patch deleted file mode 100644 index b607c1afe9..0000000000 --- a/patches/server/0316-Validate-tripwire-hook-placement-before-update.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sat, 7 Mar 2020 00:07:51 +0000 -Subject: [PATCH] Validate tripwire hook placement before update - - -diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java -index 1240f18b3d40f8bde2346c893304ae340a727e24..c2589f42c467ca672417c24076313da51bb2dcbb 100644 ---- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java -@@ -191,6 +191,7 @@ public class TripWireHookBlock extends Block { - - TripWireHookBlock.emitState(world, pos, flag4, flag5, flag2, flag3); - if (!flag) { -+ if (world.getBlockState(pos).getBlock() == Blocks.TRIPWIRE_HOOK) // Paper - Validate tripwire hook placement before update - world.setBlock(pos, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection), 3); - if (flag1) { - TripWireHookBlock.notifyNeighbors(block, world, pos, enumdirection); diff --git a/patches/server/0317-Add-option-to-allow-iron-golems-to-spawn-in-air.patch b/patches/server/0317-Add-option-to-allow-iron-golems-to-spawn-in-air.patch deleted file mode 100644 index 8991de1b70..0000000000 --- a/patches/server/0317-Add-option-to-allow-iron-golems-to-spawn-in-air.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 13 Apr 2019 16:50:58 -0500 -Subject: [PATCH] Add option to allow iron golems to spawn in air - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -index dac63f51fc23cc7f35ee299d1e04c96c210db52b..e07b79ef172095c1800c88342b3ac8dc7703aea2 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -@@ -319,7 +319,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - BlockPos blockposition1 = blockposition.below(); - BlockState iblockdata = world.getBlockState(blockposition1); - -- if (!iblockdata.entityCanStandOn(world, blockposition1, this)) { -+ if (!iblockdata.entityCanStandOn(world, blockposition1, this) && !this.level().paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper - Add option to allow iron golems to spawn in air - return false; - } else { - for (int i = 1; i < 3; ++i) { diff --git a/patches/server/0317-Configurable-chance-of-villager-zombie-infection.patch b/patches/server/0317-Configurable-chance-of-villager-zombie-infection.patch new file mode 100644 index 0000000000..e26452bb88 --- /dev/null +++ b/patches/server/0317-Configurable-chance-of-villager-zombie-infection.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zero +Date: Sat, 22 Feb 2020 16:10:31 -0500 +Subject: [PATCH] Configurable chance of villager zombie infection + +This allows you to solve an issue in vanilla behavior where: +* On easy difficulty your villagers will NEVER get infected, meaning they will always die. +* On normal difficulty they will have a 50% of getting infected or dying. + +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 d3d1e170380e7674c9ac13b06186eb563a58cd64..5b8ac7113eb8a57fe07bfaacc1b1320383a56d06 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java +@@ -484,10 +484,8 @@ public class Zombie extends Monster { + public boolean killedEntity(ServerLevel world, LivingEntity other) { + boolean flag = super.killedEntity(world, other); + +- if ((world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager entityvillager) { +- if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { +- return flag; +- } ++ final double fallbackChance = world.getDifficulty() == Difficulty.HARD ? 100d : world.getDifficulty() == Difficulty.NORMAL ? 50d : 0d; // Paper - Configurable chance of villager zombie infection ++ if (this.random.nextDouble() * 100 < world.paperConfig().entities.behavior.zombieVillagerInfectionChance.or(fallbackChance) && other instanceof Villager entityvillager) { // Paper - Configurable chance of villager zombie infection + + if (this.convertVillagerToZombieVillager(world, entityvillager)) { + flag = false; diff --git a/patches/server/0318-Configurable-chance-of-villager-zombie-infection.patch b/patches/server/0318-Configurable-chance-of-villager-zombie-infection.patch deleted file mode 100644 index e26452bb88..0000000000 --- a/patches/server/0318-Configurable-chance-of-villager-zombie-infection.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zero -Date: Sat, 22 Feb 2020 16:10:31 -0500 -Subject: [PATCH] Configurable chance of villager zombie infection - -This allows you to solve an issue in vanilla behavior where: -* On easy difficulty your villagers will NEVER get infected, meaning they will always die. -* On normal difficulty they will have a 50% of getting infected or dying. - -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 d3d1e170380e7674c9ac13b06186eb563a58cd64..5b8ac7113eb8a57fe07bfaacc1b1320383a56d06 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -484,10 +484,8 @@ public class Zombie extends Monster { - public boolean killedEntity(ServerLevel world, LivingEntity other) { - boolean flag = super.killedEntity(world, other); - -- if ((world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager entityvillager) { -- if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { -- return flag; -- } -+ final double fallbackChance = world.getDifficulty() == Difficulty.HARD ? 100d : world.getDifficulty() == Difficulty.NORMAL ? 50d : 0d; // Paper - Configurable chance of villager zombie infection -+ if (this.random.nextDouble() * 100 < world.paperConfig().entities.behavior.zombieVillagerInfectionChance.or(fallbackChance) && other instanceof Villager entityvillager) { // Paper - Configurable chance of villager zombie infection - - if (this.convertVillagerToZombieVillager(world, entityvillager)) { - flag = false; diff --git a/patches/server/0318-Optimise-Chunk-getFluid.patch b/patches/server/0318-Optimise-Chunk-getFluid.patch new file mode 100644 index 0000000000..05f68c017f --- /dev/null +++ b/patches/server/0318-Optimise-Chunk-getFluid.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Tue, 14 Jan 2020 14:59:08 -0800 +Subject: [PATCH] Optimise Chunk#getFluid + +Removing the try catch and generally reducing ops should make it +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 31696856600db18d1dc401b7fa72a7c9ff219304..b6fb9014d0e4de35b0f5a7e9e99f9db7ec89edcd 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -298,18 +298,20 @@ public class LevelChunk extends ChunkAccess { + } + + public FluidState getFluidState(int x, int y, int z) { +- try { +- int l = this.getSectionIndex(y); +- +- if (l >= 0 && l < this.sections.length) { +- LevelChunkSection chunksection = this.sections[l]; ++ // Paper start - Perf: Optimise Chunk#getFluid ++ // try { // Remove try catch ++ int index = this.getSectionIndex(y); ++ if (index >= 0 && index < this.sections.length) { ++ LevelChunkSection chunksection = this.sections[index]; + + if (!chunksection.hasOnlyAir()) { +- return chunksection.getFluidState(x & 15, y & 15, z & 15); ++ return chunksection.states.get((y & 15) << 8 | (z & 15) << 4 | x & 15).getFluidState(); ++ // Paper end - Perf: Optimise Chunk#getFluid + } + } + + return Fluids.EMPTY.defaultFluidState(); ++ /* // Paper - Perf: Optimise Chunk#getFluid + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state"); + CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got"); +@@ -319,6 +321,7 @@ public class LevelChunk extends ChunkAccess { + }); + throw new ReportedException(crashreport); + } ++ */ // Paper - Perf: Optimise Chunk#getFluid + } + + // CraftBukkit start +diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java +index 771529ba28a16664ad19ed9c0f4bf95eeb7da76b..52f44f14bbda60fe771c351e01e6ff470d7371e6 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java +@@ -49,7 +49,7 @@ public class LevelChunkSection { + } + + public FluidState getFluidState(int x, int y, int z) { +- return ((BlockState) this.states.get(x, y, z)).getFluidState(); ++ return this.states.get(x, y, z).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid; diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid. + } + + public void acquire() { diff --git a/patches/server/0319-Optimise-Chunk-getFluid.patch b/patches/server/0319-Optimise-Chunk-getFluid.patch deleted file mode 100644 index 05f68c017f..0000000000 --- a/patches/server/0319-Optimise-Chunk-getFluid.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Tue, 14 Jan 2020 14:59:08 -0800 -Subject: [PATCH] Optimise Chunk#getFluid - -Removing the try catch and generally reducing ops should make it -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 31696856600db18d1dc401b7fa72a7c9ff219304..b6fb9014d0e4de35b0f5a7e9e99f9db7ec89edcd 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -298,18 +298,20 @@ public class LevelChunk extends ChunkAccess { - } - - public FluidState getFluidState(int x, int y, int z) { -- try { -- int l = this.getSectionIndex(y); -- -- if (l >= 0 && l < this.sections.length) { -- LevelChunkSection chunksection = this.sections[l]; -+ // Paper start - Perf: Optimise Chunk#getFluid -+ // try { // Remove try catch -+ int index = this.getSectionIndex(y); -+ if (index >= 0 && index < this.sections.length) { -+ LevelChunkSection chunksection = this.sections[index]; - - if (!chunksection.hasOnlyAir()) { -- return chunksection.getFluidState(x & 15, y & 15, z & 15); -+ return chunksection.states.get((y & 15) << 8 | (z & 15) << 4 | x & 15).getFluidState(); -+ // Paper end - Perf: Optimise Chunk#getFluid - } - } - - return Fluids.EMPTY.defaultFluidState(); -+ /* // Paper - Perf: Optimise Chunk#getFluid - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state"); - CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got"); -@@ -319,6 +321,7 @@ public class LevelChunk extends ChunkAccess { - }); - throw new ReportedException(crashreport); - } -+ */ // Paper - Perf: Optimise Chunk#getFluid - } - - // CraftBukkit start -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -index 771529ba28a16664ad19ed9c0f4bf95eeb7da76b..52f44f14bbda60fe771c351e01e6ff470d7371e6 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -49,7 +49,7 @@ public class LevelChunkSection { - } - - public FluidState getFluidState(int x, int y, int z) { -- return ((BlockState) this.states.get(x, y, z)).getFluidState(); -+ return this.states.get(x, y, z).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid; diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid. - } - - public void acquire() { diff --git a/patches/server/0319-Set-spigots-verbose-world-setting-to-false-by-def.patch b/patches/server/0319-Set-spigots-verbose-world-setting-to-false-by-def.patch new file mode 100644 index 0000000000..d6e5084490 --- /dev/null +++ b/patches/server/0319-Set-spigots-verbose-world-setting-to-false-by-def.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Dec 2020 20:17:54 -0800 +Subject: [PATCH] Set spigots verbose world setting to false by def + + +diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java +index c4acaec8d331b4600c7b8b28fa969de9645938da..491dd55b2870093184a606efabd251c68cc24719 100644 +--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java ++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java +@@ -20,7 +20,7 @@ public class SpigotWorldConfig + + public void init() + { +- this.verbose = this.getBoolean( "verbose", true ); ++ this.verbose = this.getBoolean( "verbose", false ); // Paper + + this.log( "-------- World Settings For [" + this.worldName + "] --------" ); + SpigotConfig.readConfig( SpigotWorldConfig.class, this ); diff --git a/patches/server/0320-Add-tick-times-API-and-mspt-command.patch b/patches/server/0320-Add-tick-times-API-and-mspt-command.patch new file mode 100644 index 0000000000..fc732e1f3d --- /dev/null +++ b/patches/server/0320-Add-tick-times-API-and-mspt-command.patch @@ -0,0 +1,208 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 5 Apr 2020 22:23:14 -0500 +Subject: [PATCH] Add tick times API and /mspt command + + +diff --git a/src/main/java/io/papermc/paper/command/MSPTCommand.java b/src/main/java/io/papermc/paper/command/MSPTCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8b5293b0c696ef21d0101493ffa41b60bf0bc86b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/MSPTCommand.java +@@ -0,0 +1,102 @@ ++package io.papermc.paper.command; ++ ++import net.kyori.adventure.text.Component; ++import net.minecraft.server.MinecraftServer; ++import org.bukkit.Location; ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandSender; ++ ++import java.text.DecimalFormat; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.Collections; ++import java.util.List; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++import static net.kyori.adventure.text.Component.text; ++import static net.kyori.adventure.text.format.NamedTextColor.GOLD; ++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.YELLOW; ++ ++@DefaultQualifier(NonNull.class) ++public final class MSPTCommand extends Command { ++ private static final DecimalFormat DF = new DecimalFormat("########0.0"); ++ private static final Component SLASH = text("/"); ++ ++ public MSPTCommand(final String name) { ++ super(name); ++ this.description = "View server tick times"; ++ this.usageMessage = "/mspt"; ++ this.setPermission("bukkit.command.mspt"); ++ } ++ ++ @Override ++ public List tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException { ++ return Collections.emptyList(); ++ } ++ ++ @Override ++ public boolean execute(CommandSender sender, String commandLabel, String[] args) { ++ if (!testPermission(sender)) return true; ++ ++ MinecraftServer server = MinecraftServer.getServer(); ++ ++ List times = new ArrayList<>(); ++ times.addAll(eval(server.tickTimes5s.getTimes())); ++ times.addAll(eval(server.tickTimes10s.getTimes())); ++ times.addAll(eval(server.tickTimes60s.getTimes())); ++ ++ sender.sendMessage(text().content("Server tick times ").color(GOLD) ++ .append(text().color(YELLOW) ++ .append( ++ text("("), ++ text("avg", GRAY), ++ text("/"), ++ text("min", GRAY), ++ text("/"), ++ text("max", GRAY), ++ text(")") ++ ) ++ ).append( ++ text(" from last 5s"), ++ text(",", GRAY), ++ text(" 10s"), ++ text(",", GRAY), ++ text(" 1m"), ++ text(":", YELLOW) ++ ) ++ ); ++ sender.sendMessage(text().content("â—´ ").color(GOLD) ++ .append(text().color(GRAY) ++ .append( ++ times.get(0), SLASH, times.get(1), SLASH, times.get(2), text(", ", YELLOW), ++ times.get(3), SLASH, times.get(4), SLASH, times.get(5), text(", ", YELLOW), ++ times.get(6), SLASH, times.get(7), SLASH, times.get(8) ++ ) ++ ) ++ ); ++ return true; ++ } ++ ++ private static List eval(long[] times) { ++ long min = Integer.MAX_VALUE; ++ long max = 0L; ++ long total = 0L; ++ for (long value : times) { ++ if (value > 0L && value < min) min = value; ++ if (value > max) max = value; ++ total += value; ++ } ++ double avgD = ((double) total / (double) times.length) * 1.0E-6D; ++ double minD = ((double) min) * 1.0E-6D; ++ double maxD = ((double) max) * 1.0E-6D; ++ return Arrays.asList(getColor(avgD), getColor(minD), getColor(maxD)); ++ } ++ ++ private static Component getColor(double avg) { ++ return text(DF.format(avg), avg >= 50 ? RED : avg >= 40 ? YELLOW : GREEN); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java +index 72f2e81b9905a0d57ed8e2a88578f62d5235c456..7b58b2d6297800c2dcdbf7539e5ab8e7703f39f1 100644 +--- a/src/main/java/io/papermc/paper/command/PaperCommands.java ++++ b/src/main/java/io/papermc/paper/command/PaperCommands.java +@@ -18,6 +18,7 @@ public final class PaperCommands { + static { + COMMANDS.put("paper", new PaperCommand("paper")); + COMMANDS.put("callback", new CallbackCommand("callback")); ++ COMMANDS.put("mspt", new MSPTCommand("mspt")); + } + + 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 a7eeb4f3098a4bea05592890b5fecbfbac3090e4..e1a15f3721e3c661be0185d65073a39f293f0589 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -263,6 +263,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Wed, 2 Dec 2020 20:17:54 -0800 -Subject: [PATCH] Set spigots verbose world setting to false by def - - -diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java -index c4acaec8d331b4600c7b8b28fa969de9645938da..491dd55b2870093184a606efabd251c68cc24719 100644 ---- a/src/main/java/org/spigotmc/SpigotWorldConfig.java -+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java -@@ -20,7 +20,7 @@ public class SpigotWorldConfig - - public void init() - { -- this.verbose = this.getBoolean( "verbose", true ); -+ this.verbose = this.getBoolean( "verbose", false ); // Paper - - this.log( "-------- World Settings For [" + this.worldName + "] --------" ); - SpigotConfig.readConfig( SpigotWorldConfig.class, this ); diff --git a/patches/server/0321-Add-tick-times-API-and-mspt-command.patch b/patches/server/0321-Add-tick-times-API-and-mspt-command.patch deleted file mode 100644 index fc732e1f3d..0000000000 --- a/patches/server/0321-Add-tick-times-API-and-mspt-command.patch +++ /dev/null @@ -1,208 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 5 Apr 2020 22:23:14 -0500 -Subject: [PATCH] Add tick times API and /mspt command - - -diff --git a/src/main/java/io/papermc/paper/command/MSPTCommand.java b/src/main/java/io/papermc/paper/command/MSPTCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8b5293b0c696ef21d0101493ffa41b60bf0bc86b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/MSPTCommand.java -@@ -0,0 +1,102 @@ -+package io.papermc.paper.command; -+ -+import net.kyori.adventure.text.Component; -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.Location; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+ -+import java.text.DecimalFormat; -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Collections; -+import java.util.List; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+import static net.kyori.adventure.text.Component.text; -+import static net.kyori.adventure.text.format.NamedTextColor.GOLD; -+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.YELLOW; -+ -+@DefaultQualifier(NonNull.class) -+public final class MSPTCommand extends Command { -+ private static final DecimalFormat DF = new DecimalFormat("########0.0"); -+ private static final Component SLASH = text("/"); -+ -+ public MSPTCommand(final String name) { -+ super(name); -+ this.description = "View server tick times"; -+ this.usageMessage = "/mspt"; -+ this.setPermission("bukkit.command.mspt"); -+ } -+ -+ @Override -+ public List tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException { -+ return Collections.emptyList(); -+ } -+ -+ @Override -+ public boolean execute(CommandSender sender, String commandLabel, String[] args) { -+ if (!testPermission(sender)) return true; -+ -+ MinecraftServer server = MinecraftServer.getServer(); -+ -+ List times = new ArrayList<>(); -+ times.addAll(eval(server.tickTimes5s.getTimes())); -+ times.addAll(eval(server.tickTimes10s.getTimes())); -+ times.addAll(eval(server.tickTimes60s.getTimes())); -+ -+ sender.sendMessage(text().content("Server tick times ").color(GOLD) -+ .append(text().color(YELLOW) -+ .append( -+ text("("), -+ text("avg", GRAY), -+ text("/"), -+ text("min", GRAY), -+ text("/"), -+ text("max", GRAY), -+ text(")") -+ ) -+ ).append( -+ text(" from last 5s"), -+ text(",", GRAY), -+ text(" 10s"), -+ text(",", GRAY), -+ text(" 1m"), -+ text(":", YELLOW) -+ ) -+ ); -+ sender.sendMessage(text().content("â—´ ").color(GOLD) -+ .append(text().color(GRAY) -+ .append( -+ times.get(0), SLASH, times.get(1), SLASH, times.get(2), text(", ", YELLOW), -+ times.get(3), SLASH, times.get(4), SLASH, times.get(5), text(", ", YELLOW), -+ times.get(6), SLASH, times.get(7), SLASH, times.get(8) -+ ) -+ ) -+ ); -+ return true; -+ } -+ -+ private static List eval(long[] times) { -+ long min = Integer.MAX_VALUE; -+ long max = 0L; -+ long total = 0L; -+ for (long value : times) { -+ if (value > 0L && value < min) min = value; -+ if (value > max) max = value; -+ total += value; -+ } -+ double avgD = ((double) total / (double) times.length) * 1.0E-6D; -+ double minD = ((double) min) * 1.0E-6D; -+ double maxD = ((double) max) * 1.0E-6D; -+ return Arrays.asList(getColor(avgD), getColor(minD), getColor(maxD)); -+ } -+ -+ private static Component getColor(double avg) { -+ return text(DF.format(avg), avg >= 50 ? RED : avg >= 40 ? YELLOW : GREEN); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java -index 72f2e81b9905a0d57ed8e2a88578f62d5235c456..7b58b2d6297800c2dcdbf7539e5ab8e7703f39f1 100644 ---- a/src/main/java/io/papermc/paper/command/PaperCommands.java -+++ b/src/main/java/io/papermc/paper/command/PaperCommands.java -@@ -18,6 +18,7 @@ public final class PaperCommands { - static { - COMMANDS.put("paper", new PaperCommand("paper")); - COMMANDS.put("callback", new CallbackCommand("callback")); -+ COMMANDS.put("mspt", new MSPTCommand("mspt")); - } - - 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 a7eeb4f3098a4bea05592890b5fecbfbac3090e4..e1a15f3721e3c661be0185d65073a39f293f0589 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -263,6 +263,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Fri, 10 Apr 2020 21:24:12 -0400 +Subject: [PATCH] Expose MinecraftServer#isRunning + +This allows for plugins to detect if the server is actually turning off in onDisable rather than just plugins reloading. + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 1b80d12515141fb6a6b33475a086d85d437e60a5..e9391811dc6ff954bdf1854e1e33e96931bcd2ac 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2960,5 +2960,10 @@ public final class CraftServer implements Server { + public int getCurrentTick() { + return net.minecraft.server.MinecraftServer.currentTick; + } ++ ++ @Override ++ public boolean isStopping() { ++ return net.minecraft.server.MinecraftServer.getServer().hasStopped(); ++ } + // Paper end + } diff --git a/patches/server/0322-Add-Raw-Byte-ItemStack-Serialization.patch b/patches/server/0322-Add-Raw-Byte-ItemStack-Serialization.patch new file mode 100644 index 0000000000..9389066286 --- /dev/null +++ b/patches/server/0322-Add-Raw-Byte-ItemStack-Serialization.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Thu, 30 Apr 2020 16:56:54 +0200 +Subject: [PATCH] Add Raw Byte ItemStack Serialization + +Serializes using NBT which is safer for server data migrations than bukkits format. + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index e27f10d0d5720c144729ce83e27aa1c70170ebe2..1e41803952f2410c8f1e213d8be8d141773853d3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -480,6 +480,53 @@ public final class CraftMagicNumbers implements UnsafeValues { + public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { + return new com.destroystokyo.paper.PaperVersionFetcher(); + } ++ ++ @Override ++ public byte[] serializeItem(ItemStack item) { ++ Preconditions.checkNotNull(item, "null cannot be serialized"); ++ Preconditions.checkArgument(item.getType() != Material.AIR, "air cannot be serialized"); ++ ++ return serializeNbtToBytes((net.minecraft.nbt.CompoundTag) (item instanceof CraftItemStack ? ((CraftItemStack) item).handle : CraftItemStack.asNMSCopy(item)).save(MinecraftServer.getServer().registryAccess())); ++ } ++ ++ @Override ++ public ItemStack deserializeItem(byte[] data) { ++ Preconditions.checkNotNull(data, "null cannot be deserialized"); ++ Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing"); ++ ++ net.minecraft.nbt.CompoundTag compound = deserializeNbtFromBytes(data); ++ final int dataVersion = compound.getInt("DataVersion"); ++ compound = (net.minecraft.nbt.CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, this.getDataVersion()).getValue(); ++ return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow()); ++ } ++ ++ private byte[] serializeNbtToBytes(CompoundTag compound) { ++ compound.putInt("DataVersion", getDataVersion()); ++ java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream(); ++ try { ++ net.minecraft.nbt.NbtIo.writeCompressed( ++ compound, ++ outputStream ++ ); ++ } catch (IOException ex) { ++ throw new RuntimeException(ex); ++ } ++ return outputStream.toByteArray(); ++ } ++ ++ private net.minecraft.nbt.CompoundTag deserializeNbtFromBytes(byte[] data) { ++ net.minecraft.nbt.CompoundTag compound; ++ try { ++ compound = net.minecraft.nbt.NbtIo.readCompressed( ++ new java.io.ByteArrayInputStream(data), net.minecraft.nbt.NbtAccounter.unlimitedHeap() ++ ); ++ } catch (IOException ex) { ++ throw new RuntimeException(ex); ++ } ++ int dataVersion = compound.getInt("DataVersion"); ++ Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!"); ++ return compound; ++ } + // Paper end + + /** diff --git a/patches/server/0322-Expose-MinecraftServer-isRunning.patch b/patches/server/0322-Expose-MinecraftServer-isRunning.patch deleted file mode 100644 index 7a4ecb699a..0000000000 --- a/patches/server/0322-Expose-MinecraftServer-isRunning.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Fri, 10 Apr 2020 21:24:12 -0400 -Subject: [PATCH] Expose MinecraftServer#isRunning - -This allows for plugins to detect if the server is actually turning off in onDisable rather than just plugins reloading. - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 1b80d12515141fb6a6b33475a086d85d437e60a5..e9391811dc6ff954bdf1854e1e33e96931bcd2ac 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2960,5 +2960,10 @@ public final class CraftServer implements Server { - public int getCurrentTick() { - return net.minecraft.server.MinecraftServer.currentTick; - } -+ -+ @Override -+ public boolean isStopping() { -+ return net.minecraft.server.MinecraftServer.getServer().hasStopped(); -+ } - // Paper end - } diff --git a/patches/server/0323-Add-Raw-Byte-ItemStack-Serialization.patch b/patches/server/0323-Add-Raw-Byte-ItemStack-Serialization.patch deleted file mode 100644 index 9389066286..0000000000 --- a/patches/server/0323-Add-Raw-Byte-ItemStack-Serialization.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Thu, 30 Apr 2020 16:56:54 +0200 -Subject: [PATCH] Add Raw Byte ItemStack Serialization - -Serializes using NBT which is safer for server data migrations than bukkits format. - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index e27f10d0d5720c144729ce83e27aa1c70170ebe2..1e41803952f2410c8f1e213d8be8d141773853d3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -480,6 +480,53 @@ public final class CraftMagicNumbers implements UnsafeValues { - public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { - return new com.destroystokyo.paper.PaperVersionFetcher(); - } -+ -+ @Override -+ public byte[] serializeItem(ItemStack item) { -+ Preconditions.checkNotNull(item, "null cannot be serialized"); -+ Preconditions.checkArgument(item.getType() != Material.AIR, "air cannot be serialized"); -+ -+ return serializeNbtToBytes((net.minecraft.nbt.CompoundTag) (item instanceof CraftItemStack ? ((CraftItemStack) item).handle : CraftItemStack.asNMSCopy(item)).save(MinecraftServer.getServer().registryAccess())); -+ } -+ -+ @Override -+ public ItemStack deserializeItem(byte[] data) { -+ Preconditions.checkNotNull(data, "null cannot be deserialized"); -+ Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing"); -+ -+ net.minecraft.nbt.CompoundTag compound = deserializeNbtFromBytes(data); -+ final int dataVersion = compound.getInt("DataVersion"); -+ compound = (net.minecraft.nbt.CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, this.getDataVersion()).getValue(); -+ return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow()); -+ } -+ -+ private byte[] serializeNbtToBytes(CompoundTag compound) { -+ compound.putInt("DataVersion", getDataVersion()); -+ java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream(); -+ try { -+ net.minecraft.nbt.NbtIo.writeCompressed( -+ compound, -+ outputStream -+ ); -+ } catch (IOException ex) { -+ throw new RuntimeException(ex); -+ } -+ return outputStream.toByteArray(); -+ } -+ -+ private net.minecraft.nbt.CompoundTag deserializeNbtFromBytes(byte[] data) { -+ net.minecraft.nbt.CompoundTag compound; -+ try { -+ compound = net.minecraft.nbt.NbtIo.readCompressed( -+ new java.io.ByteArrayInputStream(data), net.minecraft.nbt.NbtAccounter.unlimitedHeap() -+ ); -+ } catch (IOException ex) { -+ throw new RuntimeException(ex); -+ } -+ int dataVersion = compound.getInt("DataVersion"); -+ Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!"); -+ return compound; -+ } - // Paper end - - /** diff --git a/patches/server/0323-Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/0323-Pillager-patrol-spawn-settings-and-per-player-option.patch new file mode 100644 index 0000000000..5eefab8ebc --- /dev/null +++ b/patches/server/0323-Pillager-patrol-spawn-settings-and-per-player-option.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 +Date: Sat, 1 Feb 2020 16:50:39 +0100 +Subject: [PATCH] Pillager patrol spawn settings and per player options + +This adds config options for defining the spawn chance, spawn delay and +spawn start day as well as toggles for handling the spawn delay and +start day per player. (Based on the time played statistic) +When not per player it will use the Vanilla mechanic of one delay per +world and the world age for the start day. + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 9b194fcae767647b719ca687d0574ef74dc310da..6a282b80e062a0dd769c0d94357bce9a40240200 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -295,6 +295,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + public boolean wonGame; + private int containerUpdateDelay; // Paper - Configurable container update tick rate + public long loginTime; // Paper - Replace OfflinePlayer#getLastPlayed ++ public int patrolSpawnDelay; // Paper - Pillager patrol spawn settings and per player options + // Paper start - cancellable death event + public boolean queueHealthUpdatePacket; + public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket; +diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java +index 8837db46ced2412942949a3c6f81ec7d9a0bacda..e93ef232b0426a1095dad05fc4acb2a74db5b689 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java +@@ -24,7 +24,7 @@ public class PatrolSpawner implements CustomSpawner { + + @Override + public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { +- if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper - Add option to disable pillager patrols ++ if (world.paperConfig().entities.behavior.pillagerPatrols.disable || world.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return 0; // Paper - Add option to disable pillager patrols & Pillager patrol spawn settings and per player options + if (!spawnMonsters) { + return 0; + } else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) { +@@ -32,23 +32,51 @@ public class PatrolSpawner implements CustomSpawner { + } else { + RandomSource randomsource = world.random; + +- --this.nextTick; +- if (this.nextTick > 0) { ++ // Paper start - Pillager patrol spawn settings and per player options ++ // Random player selection moved up for per player spawning and configuration ++ int j = world.players().size(); ++ if (j < 1) { + return 0; ++ } ++ ++ net.minecraft.server.level.ServerPlayer entityhuman = world.players().get(randomsource.nextInt(j)); ++ if (entityhuman.isSpectator()) { ++ return 0; ++ } ++ ++ int patrolSpawnDelay; ++ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { ++ --entityhuman.patrolSpawnDelay; ++ patrolSpawnDelay = entityhuman.patrolSpawnDelay; + } else { +- this.nextTick += 12000 + randomsource.nextInt(1200); +- long i = world.getDayTime() / 24000L; ++ this.nextTick--; ++ patrolSpawnDelay = this.nextTick; ++ } ++ ++ if (patrolSpawnDelay > 0) { ++ return 0; ++ } else { ++ long days; ++ if (world.paperConfig().entities.behavior.pillagerPatrols.start.perPlayer) { ++ days = entityhuman.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.PLAY_TIME)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang ++ } else { ++ days = world.getDayTime() / 24000L; ++ } ++ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { ++ entityhuman.patrolSpawnDelay += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200); ++ } else { ++ this.nextTick += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200); ++ } + +- if (i >= 5L && world.isDay()) { +- if (randomsource.nextInt(5) != 0) { ++ if (days >= world.paperConfig().entities.behavior.pillagerPatrols.start.day && world.isDay()) { ++ if (randomsource.nextDouble() >= world.paperConfig().entities.behavior.pillagerPatrols.spawnChance) { ++ // Paper end - Pillager patrol spawn settings and per player options + return 0; + } else { +- int j = world.players().size(); + + if (j < 1) { + return 0; + } else { +- Player entityhuman = (Player) world.players().get(randomsource.nextInt(j)); + + if (entityhuman.isSpectator()) { + return 0; diff --git a/patches/server/0324-Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/0324-Pillager-patrol-spawn-settings-and-per-player-option.patch deleted file mode 100644 index 9ff443b665..0000000000 --- a/patches/server/0324-Pillager-patrol-spawn-settings-and-per-player-option.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Sat, 1 Feb 2020 16:50:39 +0100 -Subject: [PATCH] Pillager patrol spawn settings and per player options - -This adds config options for defining the spawn chance, spawn delay and -spawn start day as well as toggles for handling the spawn delay and -start day per player. (Based on the time played statistic) -When not per player it will use the Vanilla mechanic of one delay per -world and the world age for the start day. - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index a624cab05e9a4308a7f887f9edcf0ec1555f94a8..df409f2dc2c49282f128a9fdd9c248a2f6d9a7c9 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -295,6 +295,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - public boolean wonGame; - private int containerUpdateDelay; // Paper - Configurable container update tick rate - public long loginTime; // Paper - Replace OfflinePlayer#getLastPlayed -+ public int patrolSpawnDelay; // Paper - Pillager patrol spawn settings and per player options - // Paper start - cancellable death event - public boolean queueHealthUpdatePacket; - public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket; -diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java -index 8837db46ced2412942949a3c6f81ec7d9a0bacda..e93ef232b0426a1095dad05fc4acb2a74db5b689 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java -@@ -24,7 +24,7 @@ public class PatrolSpawner implements CustomSpawner { - - @Override - public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { -- if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper - Add option to disable pillager patrols -+ if (world.paperConfig().entities.behavior.pillagerPatrols.disable || world.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return 0; // Paper - Add option to disable pillager patrols & Pillager patrol spawn settings and per player options - if (!spawnMonsters) { - return 0; - } else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) { -@@ -32,23 +32,51 @@ public class PatrolSpawner implements CustomSpawner { - } else { - RandomSource randomsource = world.random; - -- --this.nextTick; -- if (this.nextTick > 0) { -+ // Paper start - Pillager patrol spawn settings and per player options -+ // Random player selection moved up for per player spawning and configuration -+ int j = world.players().size(); -+ if (j < 1) { - return 0; -+ } -+ -+ net.minecraft.server.level.ServerPlayer entityhuman = world.players().get(randomsource.nextInt(j)); -+ if (entityhuman.isSpectator()) { -+ return 0; -+ } -+ -+ int patrolSpawnDelay; -+ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { -+ --entityhuman.patrolSpawnDelay; -+ patrolSpawnDelay = entityhuman.patrolSpawnDelay; - } else { -- this.nextTick += 12000 + randomsource.nextInt(1200); -- long i = world.getDayTime() / 24000L; -+ this.nextTick--; -+ patrolSpawnDelay = this.nextTick; -+ } -+ -+ if (patrolSpawnDelay > 0) { -+ return 0; -+ } else { -+ long days; -+ if (world.paperConfig().entities.behavior.pillagerPatrols.start.perPlayer) { -+ days = entityhuman.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.PLAY_TIME)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang -+ } else { -+ days = world.getDayTime() / 24000L; -+ } -+ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { -+ entityhuman.patrolSpawnDelay += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200); -+ } else { -+ this.nextTick += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200); -+ } - -- if (i >= 5L && world.isDay()) { -- if (randomsource.nextInt(5) != 0) { -+ if (days >= world.paperConfig().entities.behavior.pillagerPatrols.start.day && world.isDay()) { -+ if (randomsource.nextDouble() >= world.paperConfig().entities.behavior.pillagerPatrols.spawnChance) { -+ // Paper end - Pillager patrol spawn settings and per player options - return 0; - } else { -- int j = world.players().size(); - - if (j < 1) { - return 0; - } else { -- Player entityhuman = (Player) world.players().get(randomsource.nextInt(j)); - - if (entityhuman.isSpectator()) { - return 0; diff --git a/patches/server/0324-Remote-Connections-shouldn-t-hold-up-shutdown.patch b/patches/server/0324-Remote-Connections-shouldn-t-hold-up-shutdown.patch new file mode 100644 index 0000000000..b9679f9f48 --- /dev/null +++ b/patches/server/0324-Remote-Connections-shouldn-t-hold-up-shutdown.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 31 Mar 2020 03:50:42 -0400 +Subject: [PATCH] Remote Connections shouldn't hold up shutdown + +Bugs in the connection logic appears to leave stale connections even, preventing shutdown + +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 417c8bf97c5f5b7d127ac7d496b86882d75ff354..fe1975675189c6d1a63c42b7959fa40b5ac95ef8 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -396,11 +396,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + } + + if (this.rconThread != null) { +- this.rconThread.stop(); ++ this.rconThread.stopNonBlocking(); // Paper - don't wait for remote connections + } + + if (this.queryThreadGs4 != null) { +- this.queryThreadGs4.stop(); ++ // this.remoteStatusListener.stop(); // Paper - don't wait for remote connections + } + + System.exit(0); // CraftBukkit +diff --git a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java +index 594fbb033b63b8c9fb8752b1fcc78f8e9f7a2a83..c12d7db2b048a327c0e8f398848cd3a9bce0ebce 100644 +--- a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java ++++ b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java +@@ -104,6 +104,14 @@ public class RconThread extends GenericThread { + + this.clients.clear(); + } ++ // Paper start - don't wait for remote connections ++ public void stopNonBlocking() { ++ this.running = false; ++ for (RconClient client : this.clients) { ++ client.running = false; ++ } ++ } ++ // Paper end - don't wait for remote connections + + private void closeSocket(ServerSocket socket) { + LOGGER.debug("closeSocket: {}", socket); diff --git a/patches/server/0325-Do-not-allow-Vexes-to-load-chunks.patch b/patches/server/0325-Do-not-allow-Vexes-to-load-chunks.patch new file mode 100644 index 0000000000..0bc83a1344 --- /dev/null +++ b/patches/server/0325-Do-not-allow-Vexes-to-load-chunks.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chickeneer +Date: Tue, 17 Mar 2020 14:18:50 -0500 +Subject: [PATCH] Do not allow Vexes to load chunks + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java +index 1a5a61f3c6587992acadc83d5dff97ae2fe53235..183a33b7d666d652b455baa7e8339e9c4a870a58 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Vex.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java +@@ -354,7 +354,10 @@ public class Vex extends Monster implements TraceableEntity { + for (int i = 0; i < 3; ++i) { + BlockPos blockposition1 = blockposition.offset(Vex.this.random.nextInt(15) - 7, Vex.this.random.nextInt(11) - 5, Vex.this.random.nextInt(15) - 7); + +- if (Vex.this.level().isEmptyBlock(blockposition1)) { ++ // Paper start - Don't load chunks ++ final net.minecraft.world.level.block.state.BlockState blockState = Vex.this.level().getBlockStateIfLoaded(blockposition1); ++ if (blockState != null && blockState.isAir()) { ++ // Paper end - Don't load chunks + Vex.this.moveControl.setWantedPosition((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.5D, (double) blockposition1.getZ() + 0.5D, 0.25D); + if (Vex.this.getTarget() == null) { + Vex.this.getLookControl().setLookAt((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.5D, (double) blockposition1.getZ() + 0.5D, 180.0F, 20.0F); diff --git a/patches/server/0325-Remote-Connections-shouldn-t-hold-up-shutdown.patch b/patches/server/0325-Remote-Connections-shouldn-t-hold-up-shutdown.patch deleted file mode 100644 index b9679f9f48..0000000000 --- a/patches/server/0325-Remote-Connections-shouldn-t-hold-up-shutdown.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 31 Mar 2020 03:50:42 -0400 -Subject: [PATCH] Remote Connections shouldn't hold up shutdown - -Bugs in the connection logic appears to leave stale connections even, preventing shutdown - -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 417c8bf97c5f5b7d127ac7d496b86882d75ff354..fe1975675189c6d1a63c42b7959fa40b5ac95ef8 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -396,11 +396,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - } - - if (this.rconThread != null) { -- this.rconThread.stop(); -+ this.rconThread.stopNonBlocking(); // Paper - don't wait for remote connections - } - - if (this.queryThreadGs4 != null) { -- this.queryThreadGs4.stop(); -+ // this.remoteStatusListener.stop(); // Paper - don't wait for remote connections - } - - System.exit(0); // CraftBukkit -diff --git a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java -index 594fbb033b63b8c9fb8752b1fcc78f8e9f7a2a83..c12d7db2b048a327c0e8f398848cd3a9bce0ebce 100644 ---- a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java -+++ b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java -@@ -104,6 +104,14 @@ public class RconThread extends GenericThread { - - this.clients.clear(); - } -+ // Paper start - don't wait for remote connections -+ public void stopNonBlocking() { -+ this.running = false; -+ for (RconClient client : this.clients) { -+ client.running = false; -+ } -+ } -+ // Paper end - don't wait for remote connections - - private void closeSocket(ServerSocket socket) { - LOGGER.debug("closeSocket: {}", socket); diff --git a/patches/server/0326-Do-not-allow-Vexes-to-load-chunks.patch b/patches/server/0326-Do-not-allow-Vexes-to-load-chunks.patch deleted file mode 100644 index 0bc83a1344..0000000000 --- a/patches/server/0326-Do-not-allow-Vexes-to-load-chunks.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: chickeneer -Date: Tue, 17 Mar 2020 14:18:50 -0500 -Subject: [PATCH] Do not allow Vexes to load chunks - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java -index 1a5a61f3c6587992acadc83d5dff97ae2fe53235..183a33b7d666d652b455baa7e8339e9c4a870a58 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vex.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java -@@ -354,7 +354,10 @@ public class Vex extends Monster implements TraceableEntity { - for (int i = 0; i < 3; ++i) { - BlockPos blockposition1 = blockposition.offset(Vex.this.random.nextInt(15) - 7, Vex.this.random.nextInt(11) - 5, Vex.this.random.nextInt(15) - 7); - -- if (Vex.this.level().isEmptyBlock(blockposition1)) { -+ // Paper start - Don't load chunks -+ final net.minecraft.world.level.block.state.BlockState blockState = Vex.this.level().getBlockStateIfLoaded(blockposition1); -+ if (blockState != null && blockState.isAir()) { -+ // Paper end - Don't load chunks - Vex.this.moveControl.setWantedPosition((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.5D, (double) blockposition1.getZ() + 0.5D, 0.25D); - if (Vex.this.getTarget() == null) { - Vex.this.getLookControl().setLookAt((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.5D, (double) blockposition1.getZ() + 0.5D, 180.0F, 20.0F); diff --git a/patches/server/0326-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch b/patches/server/0326-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch new file mode 100644 index 0000000000..d7626e4743 --- /dev/null +++ b/patches/server/0326-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 2 Apr 2020 01:42:39 -0400 +Subject: [PATCH] Prevent Double PlayerChunkMap adds crashing server + +Suspected case would be around the technique used in .stopRiding +Stack will identify any causer of this and warn instead of crashing. + +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 9baec6e78bdebd9b38b3f12e4fba99f9ad039c1e..914e9e0af7533cbf487ea0413da447d5eb8d527b 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1292,6 +1292,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + public void addEntity(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot ++ // Paper start - ignore and warn about illegal addEntity calls instead of crashing server ++ if (!entity.valid || entity.level() != this.level || this.entityMap.containsKey(entity.getId())) { ++ LOGGER.error("Illegal ChunkMap::addEntity for world " + this.level.getWorld().getName() ++ + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable()); ++ return; ++ } ++ // Paper end - ignore and warn about illegal addEntity calls instead of crashing server + if (!(entity instanceof EnderDragonPart)) { + EntityType 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 5b47505353bf96bcb555910d1ebf645d14052f46..c631ea4e75798e36cc6418b1e71eeca89c8263d5 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2217,7 +2217,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + + public void onTrackingStart(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot +- ServerLevel.this.getChunkSource().addEntity(entity); ++ // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true + if (entity instanceof ServerPlayer entityplayer) { + ServerLevel.this.players.add(entityplayer); + ServerLevel.this.updateSleepingPlayerList(); +@@ -2247,6 +2247,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 ++ ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server + // Paper start - Entity origin API + if (entity.getOriginVector() == null) { + entity.setOrigin(entity.getBukkitEntity().getLocation()); diff --git a/patches/server/0327-Don-t-tick-dead-players.patch b/patches/server/0327-Don-t-tick-dead-players.patch new file mode 100644 index 0000000000..d57954dd0b --- /dev/null +++ b/patches/server/0327-Don-t-tick-dead-players.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 2 Apr 2020 17:16:48 -0400 +Subject: [PATCH] Don't tick dead players + +Causes sync chunk loads and who knows what all else. +This is safe because Spectators are skipped in unloaded chunks too in vanilla. + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 6a282b80e062a0dd769c0d94357bce9a40240200..4d73ccb30fde83497405b6a6a788f69e0349aec1 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -990,7 +990,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + + public void doTick() { + try { +- if (!this.isSpectator() || !this.touchingUnloadedChunk()) { ++ if (valid && !this.isSpectator() || !this.touchingUnloadedChunk()) { // Paper - don't tick dead players that are not in the world currently (pending respawn) + super.tick(); + } + diff --git a/patches/server/0327-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch b/patches/server/0327-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch deleted file mode 100644 index d7626e4743..0000000000 --- a/patches/server/0327-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 2 Apr 2020 01:42:39 -0400 -Subject: [PATCH] Prevent Double PlayerChunkMap adds crashing server - -Suspected case would be around the technique used in .stopRiding -Stack will identify any causer of this and warn instead of crashing. - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 9baec6e78bdebd9b38b3f12e4fba99f9ad039c1e..914e9e0af7533cbf487ea0413da447d5eb8d527b 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1292,6 +1292,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - public void addEntity(Entity entity) { - org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot -+ // Paper start - ignore and warn about illegal addEntity calls instead of crashing server -+ if (!entity.valid || entity.level() != this.level || this.entityMap.containsKey(entity.getId())) { -+ LOGGER.error("Illegal ChunkMap::addEntity for world " + this.level.getWorld().getName() -+ + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable()); -+ return; -+ } -+ // Paper end - ignore and warn about illegal addEntity calls instead of crashing server - if (!(entity instanceof EnderDragonPart)) { - EntityType 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 5b47505353bf96bcb555910d1ebf645d14052f46..c631ea4e75798e36cc6418b1e71eeca89c8263d5 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2217,7 +2217,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - - public void onTrackingStart(Entity entity) { - org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot -- ServerLevel.this.getChunkSource().addEntity(entity); -+ // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true - if (entity instanceof ServerPlayer entityplayer) { - ServerLevel.this.players.add(entityplayer); - ServerLevel.this.updateSleepingPlayerList(); -@@ -2247,6 +2247,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 -+ ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server - // Paper start - Entity origin API - if (entity.getOriginVector() == null) { - entity.setOrigin(entity.getBukkitEntity().getLocation()); diff --git a/patches/server/0328-Dead-Player-s-shouldn-t-be-able-to-move.patch b/patches/server/0328-Dead-Player-s-shouldn-t-be-able-to-move.patch new file mode 100644 index 0000000000..705855f9ab --- /dev/null +++ b/patches/server/0328-Dead-Player-s-shouldn-t-be-able-to-move.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 2 Apr 2020 19:31:16 -0400 +Subject: [PATCH] Dead Player's shouldn't be able to move + +This fixes a lot of game state issues where packets were delayed for processing +due to 1.15's new queue but processed while dead. + +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 858f123934021b7a3911d3d5cfcb8352293a8302..c23b8f00d7ce3a46f9d104ffae5e4c6124a111ce 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -1146,7 +1146,7 @@ public abstract class Player extends LivingEntity { + + @Override + protected boolean isImmobile() { +- return super.isImmobile() || this.isSleeping(); ++ return super.isImmobile() || this.isSleeping() || this.isRemoved() || !valid; // Paper - player's who are dead or not in a world shouldn't move... + } + + @Override diff --git a/patches/server/0328-Don-t-tick-dead-players.patch b/patches/server/0328-Don-t-tick-dead-players.patch deleted file mode 100644 index f9381a4e08..0000000000 --- a/patches/server/0328-Don-t-tick-dead-players.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 2 Apr 2020 17:16:48 -0400 -Subject: [PATCH] Don't tick dead players - -Causes sync chunk loads and who knows what all else. -This is safe because Spectators are skipped in unloaded chunks too in vanilla. - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index df409f2dc2c49282f128a9fdd9c248a2f6d9a7c9..957266d14ce2b9b99f7c97289458fc837e4d665a 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -990,7 +990,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - - public void doTick() { - try { -- if (!this.isSpectator() || !this.touchingUnloadedChunk()) { -+ if (valid && !this.isSpectator() || !this.touchingUnloadedChunk()) { // Paper - don't tick dead players that are not in the world currently (pending respawn) - super.tick(); - } - diff --git a/patches/server/0329-Dead-Player-s-shouldn-t-be-able-to-move.patch b/patches/server/0329-Dead-Player-s-shouldn-t-be-able-to-move.patch deleted file mode 100644 index 705855f9ab..0000000000 --- a/patches/server/0329-Dead-Player-s-shouldn-t-be-able-to-move.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 2 Apr 2020 19:31:16 -0400 -Subject: [PATCH] Dead Player's shouldn't be able to move - -This fixes a lot of game state issues where packets were delayed for processing -due to 1.15's new queue but processed while dead. - -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 858f123934021b7a3911d3d5cfcb8352293a8302..c23b8f00d7ce3a46f9d104ffae5e4c6124a111ce 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -1146,7 +1146,7 @@ public abstract class Player extends LivingEntity { - - @Override - protected boolean isImmobile() { -- return super.isImmobile() || this.isSleeping(); -+ return super.isImmobile() || this.isSleeping() || this.isRemoved() || !valid; // Paper - player's who are dead or not in a world shouldn't move... - } - - @Override diff --git a/patches/server/0329-Don-t-move-existing-players-to-world-spawn.patch b/patches/server/0329-Don-t-move-existing-players-to-world-spawn.patch new file mode 100644 index 0000000000..96bba89a99 --- /dev/null +++ b/patches/server/0329-Don-t-move-existing-players-to-world-spawn.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 9 Apr 2020 21:20:33 -0400 +Subject: [PATCH] Don't move existing players to world spawn + +This can cause a nasty server lag the spawn chunks are not kept loaded +or they aren't finished loading yet, or if the world spawn radius is +larger than the keep loaded range. + +By skipping this, we avoid potential for a large spike on server start. + +== AT == +public net.minecraft.server.level.ServerPlayer fudgeSpawnLocation(Lnet/minecraft/server/level/ServerLevel;)V + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 4d73ccb30fde83497405b6a6a788f69e0349aec1..be5ca29b0c8e1a78fc84885bb4b1c112fefdb63b 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -417,7 +417,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + this.server = server; + this.stats = server.getPlayerList().getPlayerStats(this); + this.advancements = server.getPlayerList().getPlayerAdvancements(this); +- this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); ++ // this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); // Paper - Don't move existing players to world spawn + this.updateOptions(clientOptions); + this.object = null; + +@@ -854,7 +854,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + position = Vec3.atCenterOf(world.getSharedSpawnPos()); + } + this.setLevel(world); +- this.setPos(position); ++ this.setPosRaw(position.x(), position.y(), position.z()); // Paper - don't register to chunks yet + } + 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 768754f11d72921e1206e7bd029c94fae650ae82..d238dbd78fd18da46c703351cccc70c0b07622db 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -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 ++ player.moveTo(player.adjustSpawnLocation(worldserver1, worldserver1.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); + } + // Paper end - Entity#getEntitySpawnReason + player.setServerLevel(worldserver1); diff --git a/patches/server/0330-Don-t-move-existing-players-to-world-spawn.patch b/patches/server/0330-Don-t-move-existing-players-to-world-spawn.patch deleted file mode 100644 index 099054c278..0000000000 --- a/patches/server/0330-Don-t-move-existing-players-to-world-spawn.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 9 Apr 2020 21:20:33 -0400 -Subject: [PATCH] Don't move existing players to world spawn - -This can cause a nasty server lag the spawn chunks are not kept loaded -or they aren't finished loading yet, or if the world spawn radius is -larger than the keep loaded range. - -By skipping this, we avoid potential for a large spike on server start. - -== AT == -public net.minecraft.server.level.ServerPlayer fudgeSpawnLocation(Lnet/minecraft/server/level/ServerLevel;)V - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 957266d14ce2b9b99f7c97289458fc837e4d665a..21f7b26bbf2b3e231032b7a09fa6e82f8244f495 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -417,7 +417,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - this.server = server; - this.stats = server.getPlayerList().getPlayerStats(this); - this.advancements = server.getPlayerList().getPlayerAdvancements(this); -- this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); -+ // this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); // Paper - Don't move existing players to world spawn - this.updateOptions(clientOptions); - this.object = null; - -@@ -854,7 +854,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - position = Vec3.atCenterOf(world.getSharedSpawnPos()); - } - this.setLevel(world); -- this.setPos(position); -+ this.setPosRaw(position.x(), position.y(), position.z()); // Paper - don't register to chunks yet - } - 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 768754f11d72921e1206e7bd029c94fae650ae82..d238dbd78fd18da46c703351cccc70c0b07622db 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -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 -+ player.moveTo(player.adjustSpawnLocation(worldserver1, worldserver1.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); - } - // Paper end - Entity#getEntitySpawnReason - player.setServerLevel(worldserver1); diff --git a/patches/server/0330-Optimize-Pathfinding.patch b/patches/server/0330-Optimize-Pathfinding.patch new file mode 100644 index 0000000000..76c7c6e423 --- /dev/null +++ b/patches/server/0330-Optimize-Pathfinding.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 3 Mar 2016 02:02:07 -0600 +Subject: [PATCH] Optimize Pathfinding + +Prevents pathfinding from spamming failures for things such as +arrow attacks. + +diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java +index 436812c3bfe53358b4d76bb72d777d6661bb6d60..48c0de870a5bbf647309e69361dfb10ab56c65ab 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java ++++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java +@@ -209,13 +209,33 @@ public abstract class PathNavigation { + return this.moveTo(this.createPath(x, y, z, 1), speed); + } + ++ // Paper start - Perf: Optimise pathfinding ++ private int lastFailure = 0; ++ private int pathfindFailures = 0; ++ // Paper end - Perf: Optimise pathfinding ++ + public boolean moveTo(double x, double y, double z, int distance, double speed) { + return this.moveTo(this.createPath(x, y, z, distance), speed); + } + + public boolean moveTo(Entity entity, double speed) { ++ // Paper start - Perf: Optimise pathfinding ++ if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) { ++ return false; ++ } ++ // Paper end - Perf: Optimise pathfinding + Path path = this.createPath(entity, 1); +- return path != null && this.moveTo(path, speed); ++ // Paper start - Perf: Optimise pathfinding ++ if (path != null && this.moveTo(path, speed)) { ++ this.lastFailure = 0; ++ this.pathfindFailures = 0; ++ return true; ++ } else { ++ this.pathfindFailures++; ++ this.lastFailure = net.minecraft.server.MinecraftServer.currentTick; ++ return false; ++ } ++ // Paper end - Perf: Optimise pathfinding + } + + public boolean moveTo(@Nullable Path path, double speed) { diff --git a/patches/server/0331-Optimize-Pathfinding.patch b/patches/server/0331-Optimize-Pathfinding.patch deleted file mode 100644 index 76c7c6e423..0000000000 --- a/patches/server/0331-Optimize-Pathfinding.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 3 Mar 2016 02:02:07 -0600 -Subject: [PATCH] Optimize Pathfinding - -Prevents pathfinding from spamming failures for things such as -arrow attacks. - -diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index 436812c3bfe53358b4d76bb72d777d6661bb6d60..48c0de870a5bbf647309e69361dfb10ab56c65ab 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -@@ -209,13 +209,33 @@ public abstract class PathNavigation { - return this.moveTo(this.createPath(x, y, z, 1), speed); - } - -+ // Paper start - Perf: Optimise pathfinding -+ private int lastFailure = 0; -+ private int pathfindFailures = 0; -+ // Paper end - Perf: Optimise pathfinding -+ - public boolean moveTo(double x, double y, double z, int distance, double speed) { - return this.moveTo(this.createPath(x, y, z, distance), speed); - } - - public boolean moveTo(Entity entity, double speed) { -+ // Paper start - Perf: Optimise pathfinding -+ if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) { -+ return false; -+ } -+ // Paper end - Perf: Optimise pathfinding - Path path = this.createPath(entity, 1); -- return path != null && this.moveTo(path, speed); -+ // Paper start - Perf: Optimise pathfinding -+ if (path != null && this.moveTo(path, speed)) { -+ this.lastFailure = 0; -+ this.pathfindFailures = 0; -+ return true; -+ } else { -+ this.pathfindFailures++; -+ this.lastFailure = net.minecraft.server.MinecraftServer.currentTick; -+ return false; -+ } -+ // Paper end - Perf: Optimise pathfinding - } - - public boolean moveTo(@Nullable Path path, double speed) { diff --git a/patches/server/0331-Reduce-Either-Optional-allocation.patch b/patches/server/0331-Reduce-Either-Optional-allocation.patch new file mode 100644 index 0000000000..d42e0ac184 --- /dev/null +++ b/patches/server/0331-Reduce-Either-Optional-allocation.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 6 Apr 2020 18:35:09 -0700 +Subject: [PATCH] Reduce Either Optional allocation + +In order to get chunk values, we shouldn't need to create +an optional each time. + +diff --git a/src/main/java/com/mojang/datafixers/util/Either.java b/src/main/java/com/mojang/datafixers/util/Either.java +index 698ff6caf5924ce5c731254acd466c381c55c9b3..d54e617fc583ae7a045ebba8fde6bc5a486d73d5 100644 +--- a/src/main/java/com/mojang/datafixers/util/Either.java ++++ b/src/main/java/com/mojang/datafixers/util/Either.java +@@ -22,7 +22,7 @@ public abstract class Either implements App, L> { + } + + private static final class Left extends Either { +- private final L value; ++ private final L value; private Optional valueOptional; // Paper - Perf: Reduce Either Optional allocation + + public Left(final L value) { + this.value = value; +@@ -51,7 +51,7 @@ public abstract class Either implements App, L> { + + @Override + public Optional left() { +- return Optional.of(value); ++ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - Perf: Reduce Either Optional allocation + } + + @Override +@@ -83,7 +83,7 @@ public abstract class Either implements App, L> { + } + + private static final class Right extends Either { +- private final R value; ++ private final R value; private Optional valueOptional; // Paper - Perf: Reduce Either Optional allocation + + public Right(final R value) { + this.value = value; +@@ -117,7 +117,7 @@ public abstract class Either implements App, L> { + + @Override + public Optional right() { +- return Optional.of(value); ++ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - Perf: Reduce Either Optional allocation + } + + @Override diff --git a/patches/server/0332-Reduce-Either-Optional-allocation.patch b/patches/server/0332-Reduce-Either-Optional-allocation.patch deleted file mode 100644 index d42e0ac184..0000000000 --- a/patches/server/0332-Reduce-Either-Optional-allocation.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 6 Apr 2020 18:35:09 -0700 -Subject: [PATCH] Reduce Either Optional allocation - -In order to get chunk values, we shouldn't need to create -an optional each time. - -diff --git a/src/main/java/com/mojang/datafixers/util/Either.java b/src/main/java/com/mojang/datafixers/util/Either.java -index 698ff6caf5924ce5c731254acd466c381c55c9b3..d54e617fc583ae7a045ebba8fde6bc5a486d73d5 100644 ---- a/src/main/java/com/mojang/datafixers/util/Either.java -+++ b/src/main/java/com/mojang/datafixers/util/Either.java -@@ -22,7 +22,7 @@ public abstract class Either implements App, L> { - } - - private static final class Left extends Either { -- private final L value; -+ private final L value; private Optional valueOptional; // Paper - Perf: Reduce Either Optional allocation - - public Left(final L value) { - this.value = value; -@@ -51,7 +51,7 @@ public abstract class Either implements App, L> { - - @Override - public Optional left() { -- return Optional.of(value); -+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - Perf: Reduce Either Optional allocation - } - - @Override -@@ -83,7 +83,7 @@ public abstract class Either implements App, L> { - } - - private static final class Right extends Either { -- private final R value; -+ private final R value; private Optional valueOptional; // Paper - Perf: Reduce Either Optional allocation - - public Right(final R value) { - this.value = value; -@@ -117,7 +117,7 @@ public abstract class Either implements App, L> { - - @Override - public Optional right() { -- return Optional.of(value); -+ return this.valueOptional == null ? this.valueOptional = Optional.of(this.value) : this.valueOptional; // Paper - Perf: Reduce Either Optional allocation - } - - @Override diff --git a/patches/server/0332-Reduce-memory-footprint-of-CompoundTag.patch b/patches/server/0332-Reduce-memory-footprint-of-CompoundTag.patch new file mode 100644 index 0000000000..c29c346e90 --- /dev/null +++ b/patches/server/0332-Reduce-memory-footprint-of-CompoundTag.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 6 Apr 2020 17:39:25 -0700 +Subject: [PATCH] Reduce memory footprint of CompoundTag + +Fastutil maps are going to have a lower memory footprint - which +is important because we clone chunk data after reading it for safety. +So, reduce the impact of the clone on GC. + +diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java +index d721ae6d9b54cbace5b7ade657e9739fc7c42d14..e88161e662d5605b50aead673c9b3794874e5f7f 100644 +--- a/src/main/java/net/minecraft/nbt/CompoundTag.java ++++ b/src/main/java/net/minecraft/nbt/CompoundTag.java +@@ -49,7 +49,7 @@ public class CompoundTag implements Tag { + + private static CompoundTag loadCompound(DataInput input, NbtAccounter tracker) throws IOException { + tracker.accountBytes(48L); +- Map map = Maps.newHashMap(); ++ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - Reduce memory footprint of CompoundTag + + byte b; + while ((b = input.readByte()) != 0) { +@@ -166,7 +166,7 @@ public class CompoundTag implements Tag { + } + + public CompoundTag() { +- this(Maps.newHashMap()); ++ this(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f)); // Paper - Reduce memory footprint of CompoundTag + } + + @Override +@@ -481,8 +481,16 @@ public class CompoundTag implements Tag { + + @Override + public CompoundTag copy() { +- Map map = Maps.newHashMap(Maps.transformValues(this.tags, Tag::copy)); +- return new CompoundTag(map); ++ // Paper start - Reduce memory footprint of CompoundTag ++ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.tags.size(), 0.8f); ++ java.util.Iterator> iterator = (this.tags instanceof it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ? ((it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)this.tags).object2ObjectEntrySet().fastIterator() : this.tags.entrySet().iterator(); ++ while (iterator.hasNext()) { ++ Map.Entry entry = iterator.next(); ++ ret.put(entry.getKey(), entry.getValue().copy()); ++ } ++ ++ return new CompoundTag(ret); ++ // Paper end - Reduce memory footprint of CompoundTag + } + + @Override diff --git a/patches/server/0333-Prevent-opening-inventories-when-frozen.patch b/patches/server/0333-Prevent-opening-inventories-when-frozen.patch new file mode 100644 index 0000000000..135823dafe --- /dev/null +++ b/patches/server/0333-Prevent-opening-inventories-when-frozen.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Mon, 13 Apr 2020 07:31:44 +0100 +Subject: [PATCH] Prevent opening inventories when frozen + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index be5ca29b0c8e1a78fc84885bb4b1c112fefdb63b..01afc19c566c07a1e57b57ab37d0df6095a64eac 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -935,7 +935,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + this.containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate; + } + // Paper end - Configurable container update tick rate +- if (!this.containerMenu.stillValid(this)) { ++ if (this.containerMenu != this.inventoryMenu && (this.isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - Prevent opening inventories when frozen + this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper - Inventory close reason + this.containerMenu = this.inventoryMenu; + } +@@ -1886,7 +1886,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + } else { + // CraftBukkit start + this.containerMenu = container; +- this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); ++ if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper - Prevent opening inventories when frozen + // 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 5ff159be1a6dfb4b1a5b9aa1e435d294f205215e..6ec6b80d224e2402054afb85b78c793942a58bbf 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -335,7 +335,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(container.getBukkitView().getTitle()); // Paper + + //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment +- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper ++ 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; + player.initMenu(container); + } +@@ -410,7 +410,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + 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 + //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment +- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper ++ 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; + player.initMenu(container); + } diff --git a/patches/server/0333-Reduce-memory-footprint-of-CompoundTag.patch b/patches/server/0333-Reduce-memory-footprint-of-CompoundTag.patch deleted file mode 100644 index c29c346e90..0000000000 --- a/patches/server/0333-Reduce-memory-footprint-of-CompoundTag.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 6 Apr 2020 17:39:25 -0700 -Subject: [PATCH] Reduce memory footprint of CompoundTag - -Fastutil maps are going to have a lower memory footprint - which -is important because we clone chunk data after reading it for safety. -So, reduce the impact of the clone on GC. - -diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java -index d721ae6d9b54cbace5b7ade657e9739fc7c42d14..e88161e662d5605b50aead673c9b3794874e5f7f 100644 ---- a/src/main/java/net/minecraft/nbt/CompoundTag.java -+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java -@@ -49,7 +49,7 @@ public class CompoundTag implements Tag { - - private static CompoundTag loadCompound(DataInput input, NbtAccounter tracker) throws IOException { - tracker.accountBytes(48L); -- Map map = Maps.newHashMap(); -+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - Reduce memory footprint of CompoundTag - - byte b; - while ((b = input.readByte()) != 0) { -@@ -166,7 +166,7 @@ public class CompoundTag implements Tag { - } - - public CompoundTag() { -- this(Maps.newHashMap()); -+ this(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f)); // Paper - Reduce memory footprint of CompoundTag - } - - @Override -@@ -481,8 +481,16 @@ public class CompoundTag implements Tag { - - @Override - public CompoundTag copy() { -- Map map = Maps.newHashMap(Maps.transformValues(this.tags, Tag::copy)); -- return new CompoundTag(map); -+ // Paper start - Reduce memory footprint of CompoundTag -+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.tags.size(), 0.8f); -+ java.util.Iterator> iterator = (this.tags instanceof it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ? ((it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)this.tags).object2ObjectEntrySet().fastIterator() : this.tags.entrySet().iterator(); -+ while (iterator.hasNext()) { -+ Map.Entry entry = iterator.next(); -+ ret.put(entry.getKey(), entry.getValue().copy()); -+ } -+ -+ return new CompoundTag(ret); -+ // Paper end - Reduce memory footprint of CompoundTag - } - - @Override diff --git a/patches/server/0334-Don-t-run-entity-collision-code-if-not-needed.patch b/patches/server/0334-Don-t-run-entity-collision-code-if-not-needed.patch new file mode 100644 index 0000000000..1f1a31479b --- /dev/null +++ b/patches/server/0334-Don-t-run-entity-collision-code-if-not-needed.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Wed, 15 Apr 2020 17:56:07 -0700 +Subject: [PATCH] Don't run entity collision code if not needed + +Will not run if: +Max entity cramming is disabled and the max collisions per entity is less than or equal to 0. +Entity#isPushable() returns false, meaning all entities will not be able to collide with this +entity anyways. +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 043d4e85b7021c7bec724c3aef76d1278a7d34d5..77c924d5eecd8ee7fae0c6b49d46a6c91abc969a 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3693,10 +3693,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 { ++ // Paper start - don't run getEntities if we're not going to use its result ++ if (!this.isPushable()) { ++ return; ++ } ++ net.minecraft.world.scores.Team team = this.getTeam(); ++ if (team != null && team.getCollisionRule() == net.minecraft.world.scores.Team.CollisionRule.NEVER) { ++ return; ++ } ++ ++ int i = worldserver.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); ++ if (i <= 0 && this.level().paperConfig().collisions.maxEntityCollisions <= 0) { ++ return; ++ } ++ // Paper end - don't run getEntities if we're not going to use its result + List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); + + if (!list.isEmpty()) { +- int i = worldserver.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); ++ // Paper - don't run getEntities if we're not going to use its result; moved up + + if (i > 0 && list.size() > i - 1 && this.random.nextInt(4) == 0) { + int j = 0; diff --git a/patches/server/0334-Prevent-opening-inventories-when-frozen.patch b/patches/server/0334-Prevent-opening-inventories-when-frozen.patch deleted file mode 100644 index 5df9fdb825..0000000000 --- a/patches/server/0334-Prevent-opening-inventories-when-frozen.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Mon, 13 Apr 2020 07:31:44 +0100 -Subject: [PATCH] Prevent opening inventories when frozen - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 21f7b26bbf2b3e231032b7a09fa6e82f8244f495..ba6dbbd56f5b0c2eb5566172e64fbf258f146ef0 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -935,7 +935,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - this.containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate; - } - // Paper end - Configurable container update tick rate -- if (!this.containerMenu.stillValid(this)) { -+ if (this.containerMenu != this.inventoryMenu && (this.isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - Prevent opening inventories when frozen - this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper - Inventory close reason - this.containerMenu = this.inventoryMenu; - } -@@ -1886,7 +1886,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - } else { - // CraftBukkit start - this.containerMenu = container; -- this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); -+ if (!this.isImmobile()) this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); // Paper - Prevent opening inventories when frozen - // 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 5ff159be1a6dfb4b1a5b9aa1e435d294f205215e..6ec6b80d224e2402054afb85b78c793942a58bbf 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -335,7 +335,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - if (adventure$title == null) adventure$title = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(container.getBukkitView().getTitle()); // Paper - - //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment -- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper -+ 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; - player.initMenu(container); - } -@@ -410,7 +410,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - 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 - //player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, CraftChatMessage.fromString(title)[0])); // Paper - comment -- player.connection.send(new ClientboundOpenScreenPacket(container.containerId, windowType, io.papermc.paper.adventure.PaperAdventure.asVanilla(adventure$title))); // Paper -+ 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; - player.initMenu(container); - } diff --git a/patches/server/0335-Don-t-run-entity-collision-code-if-not-needed.patch b/patches/server/0335-Don-t-run-entity-collision-code-if-not-needed.patch deleted file mode 100644 index 1f1a31479b..0000000000 --- a/patches/server/0335-Don-t-run-entity-collision-code-if-not-needed.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Wed, 15 Apr 2020 17:56:07 -0700 -Subject: [PATCH] Don't run entity collision code if not needed - -Will not run if: -Max entity cramming is disabled and the max collisions per entity is less than or equal to 0. -Entity#isPushable() returns false, meaning all entities will not be able to collide with this -entity anyways. -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 043d4e85b7021c7bec724c3aef76d1278a7d34d5..77c924d5eecd8ee7fae0c6b49d46a6c91abc969a 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3693,10 +3693,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 { -+ // Paper start - don't run getEntities if we're not going to use its result -+ if (!this.isPushable()) { -+ return; -+ } -+ net.minecraft.world.scores.Team team = this.getTeam(); -+ if (team != null && team.getCollisionRule() == net.minecraft.world.scores.Team.CollisionRule.NEVER) { -+ return; -+ } -+ -+ int i = worldserver.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); -+ if (i <= 0 && this.level().paperConfig().collisions.maxEntityCollisions <= 0) { -+ return; -+ } -+ // Paper end - don't run getEntities if we're not going to use its result - List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); - - if (!list.isEmpty()) { -- int i = worldserver.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); -+ // Paper - don't run getEntities if we're not going to use its result; moved up - - if (i > 0 && list.size() > i - 1 && this.random.nextInt(4) == 0) { - int j = 0; diff --git a/patches/server/0335-Implement-Player-Client-Options-API.patch b/patches/server/0335-Implement-Player-Client-Options-API.patch new file mode 100644 index 0000000000..11cdc881a7 --- /dev/null +++ b/patches/server/0335-Implement-Player-Client-Options-API.patch @@ -0,0 +1,200 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger +Date: Mon, 20 Jan 2020 21:38:15 +0100 +Subject: [PATCH] Implement Player Client Options API + +== AT == +public net.minecraft.world.entity.player.Player DATA_PLAYER_MODE_CUSTOMISATION +public net.minecraft.server.level.ServerPlayer particleStatus + +diff --git a/src/main/java/com/destroystokyo/paper/PaperSkinParts.java b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b6f4400df3d8ec7e06a996de54f8cabba57885e1 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java +@@ -0,0 +1,74 @@ ++package com.destroystokyo.paper; ++ ++import com.google.common.base.Objects; ++ ++import java.util.StringJoiner; ++ ++public class PaperSkinParts implements SkinParts { ++ ++ private final int raw; ++ ++ public PaperSkinParts(int raw) { ++ this.raw = raw; ++ } ++ ++ public boolean hasCapeEnabled() { ++ return (raw & 1) == 1; ++ } ++ ++ public boolean hasJacketEnabled() { ++ return (raw >> 1 & 1) == 1; ++ } ++ ++ public boolean hasLeftSleeveEnabled() { ++ return (raw >> 2 & 1) == 1; ++ } ++ ++ public boolean hasRightSleeveEnabled() { ++ return (raw >> 3 & 1) == 1; ++ } ++ ++ public boolean hasLeftPantsEnabled() { ++ return (raw >> 4 & 1) == 1; ++ } ++ ++ public boolean hasRightPantsEnabled() { ++ return (raw >> 5 & 1) == 1; ++ } ++ ++ public boolean hasHatsEnabled() { ++ return (raw >> 6 & 1) == 1; ++ } ++ ++ @Override ++ public int getRaw() { ++ return raw; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) return true; ++ if (o == null || getClass() != o.getClass()) return false; ++ PaperSkinParts that = (PaperSkinParts) o; ++ return raw == that.raw; ++ } ++ ++ @Override ++ public int hashCode() { ++ return Objects.hashCode(raw); ++ } ++ ++ @Override ++ public String toString() { ++ return new StringJoiner(", ", PaperSkinParts.class.getSimpleName() + "[", "]") ++ .add("raw=" + raw) ++ .add("cape=" + hasCapeEnabled()) ++ .add("jacket=" + hasJacketEnabled()) ++ .add("leftSleeve=" + hasLeftSleeveEnabled()) ++ .add("rightSleeve=" + hasRightSleeveEnabled()) ++ .add("leftPants=" + hasLeftPantsEnabled()) ++ .add("rightPants=" + hasRightPantsEnabled()) ++ .add("hats=" + hasHatsEnabled()) ++ .toString(); ++ } ++} +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 01afc19c566c07a1e57b57ab37d0df6095a64eac..0efa13f8eff9458318f462e42fdbffe90e21d814 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -418,7 +418,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + this.stats = server.getPlayerList().getPlayerStats(this); + this.advancements = server.getPlayerList().getPlayerAdvancements(this); + // this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); // Paper - Don't move existing players to world spawn +- this.updateOptions(clientOptions); ++ this.updateOptionsNoEvents(clientOptions); // Paper - don't call options events on login + this.object = null; + + // CraftBukkit start +@@ -2385,6 +2385,19 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + } + + public void updateOptions(ClientInformation clientOptions) { ++ // Paper start - settings event ++ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(this.getBukkitEntity(), Util.make(new java.util.IdentityHashMap<>(), map -> { ++ map.put(com.destroystokyo.paper.ClientOption.LOCALE, clientOptions.language()); ++ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, clientOptions.viewDistance()); ++ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(clientOptions.chatVisibility().name())); ++ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, clientOptions.chatColors()); ++ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, new com.destroystokyo.paper.PaperSkinParts(clientOptions.modelCustomisation())); ++ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, clientOptions.mainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT); ++ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, clientOptions.textFilteringEnabled()); ++ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, clientOptions.allowsListing()); ++ map.put(com.destroystokyo.paper.ClientOption.PARTICLE_VISIBILITY, com.destroystokyo.paper.ClientOption.ParticleVisibility.valueOf(clientOptions.particleStatus().name())); ++ })).callEvent(); ++ // Paper end - settings event + // CraftBukkit start + if (this.getMainArm() != clientOptions.mainHand()) { + PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), this.getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT); +@@ -2395,6 +2408,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + this.server.server.getPluginManager().callEvent(event); + } + // CraftBukkit end ++ // Paper start - don't call options events on login ++ this.updateOptionsNoEvents(clientOptions); ++ } ++ public void updateOptionsNoEvents(ClientInformation clientOptions) { ++ // Paper end + this.language = clientOptions.language(); + this.adventure$locale = java.util.Objects.requireNonNullElse(net.kyori.adventure.translation.Translator.parseLocale(this.language), java.util.Locale.US); // Paper + this.requestedViewDistance = clientOptions.viewDistance(); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index e548834f2bd6e1e0a510a14040cc6aca63e2e6f5..589c78cf8acc8868be686123ac893421b4848239 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -658,6 +658,30 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message); + } + } ++ ++ @Override ++ public T getClientOption(com.destroystokyo.paper.ClientOption type) { ++ if (com.destroystokyo.paper.ClientOption.SKIN_PARTS == type) { ++ return type.getType().cast(new com.destroystokyo.paper.PaperSkinParts(this.getHandle().getEntityData().get(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION))); ++ } else if (com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED == type) { ++ return type.getType().cast(this.getHandle().canChatInColor()); ++ } else if (com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY == type) { ++ return type.getType().cast(com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(this.getHandle().getChatVisibility().name())); ++ } else if (com.destroystokyo.paper.ClientOption.LOCALE == type) { ++ return type.getType().cast(this.getLocale()); ++ } else if (com.destroystokyo.paper.ClientOption.MAIN_HAND == type) { ++ return type.getType().cast(this.getMainHand()); ++ } else if (com.destroystokyo.paper.ClientOption.VIEW_DISTANCE == type) { ++ return type.getType().cast(this.getClientViewDistance()); ++ } else if (com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED == type) { ++ return type.getType().cast(this.getHandle().isTextFilteringEnabled()); ++ } else if (com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS == type) { ++ return type.getType().cast(this.getHandle().allowsListing()); ++ } else if (com.destroystokyo.paper.ClientOption.PARTICLE_VISIBILITY == type) { ++ return type.getType().cast(com.destroystokyo.paper.ClientOption.ParticleVisibility.valueOf(this.getHandle().particleStatus.name())); ++ } ++ throw new RuntimeException("Unknown settings type"); ++ } + // Paper end + + @Override +diff --git a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..01e0936ea8ce5bcacafd9e89a1c0dfd2c172024d +--- /dev/null ++++ b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.world; ++ ++import com.destroystokyo.paper.ClientOption; ++import net.minecraft.server.level.ParticleStatus; ++import net.minecraft.world.entity.player.ChatVisiblity; ++import org.junit.jupiter.api.Assertions; ++import org.junit.jupiter.api.Test; ++ ++public class TranslationKeyTest { ++ ++ @Test ++ public void testChatVisibilityKeys() { ++ for (ClientOption.ChatVisibility chatVisibility : ClientOption.ChatVisibility.values()) { ++ if (chatVisibility == ClientOption.ChatVisibility.UNKNOWN) continue; ++ Assertions.assertEquals(ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey(), chatVisibility + "'s translation key doesn't match"); ++ } ++ } ++ ++ @Test ++ public void testParticleVisibilityKeys() { ++ for (ClientOption.ParticleVisibility particleVisibility : ClientOption.ParticleVisibility.values()) { ++ Assertions.assertEquals(ParticleStatus.valueOf(particleVisibility.name()).getKey(), particleVisibility.translationKey(), particleVisibility + "'s translation key doesn't match"); ++ } ++ } ++} diff --git a/patches/server/0336-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch b/patches/server/0336-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch new file mode 100644 index 0000000000..0db5556d5a --- /dev/null +++ b/patches/server/0336-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 18 Apr 2020 15:59:41 -0400 +Subject: [PATCH] Don't crash if player is attempted to be removed from + untracked chunk. + +I suspect it deals with teleporting as it uses players current x/y/z + +diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java +index 6c2339d6a93172e25040c4868a3a47473a1f5336..f7c2c03749d6be25bf33afd61e1da120770b3432 100644 +--- a/src/main/java/net/minecraft/server/level/DistanceManager.java ++++ b/src/main/java/net/minecraft/server/level/DistanceManager.java +@@ -281,8 +281,8 @@ public abstract class DistanceManager { + ObjectSet objectset = (ObjectSet) this.playersPerChunk.get(i); + if (objectset == null) return; // CraftBukkit - SPIGOT-6208 + +- objectset.remove(player); +- if (objectset.isEmpty()) { ++ if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully ++ if (objectset == null || objectset.isEmpty()) { // Paper + this.playersPerChunk.remove(i); + this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); + this.playerTicketManager.update(i, Integer.MAX_VALUE, false); diff --git a/patches/server/0336-Implement-Player-Client-Options-API.patch b/patches/server/0336-Implement-Player-Client-Options-API.patch deleted file mode 100644 index bafe2fdfae..0000000000 --- a/patches/server/0336-Implement-Player-Client-Options-API.patch +++ /dev/null @@ -1,200 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MiniDigger -Date: Mon, 20 Jan 2020 21:38:15 +0100 -Subject: [PATCH] Implement Player Client Options API - -== AT == -public net.minecraft.world.entity.player.Player DATA_PLAYER_MODE_CUSTOMISATION -public net.minecraft.server.level.ServerPlayer particleStatus - -diff --git a/src/main/java/com/destroystokyo/paper/PaperSkinParts.java b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b6f4400df3d8ec7e06a996de54f8cabba57885e1 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/PaperSkinParts.java -@@ -0,0 +1,74 @@ -+package com.destroystokyo.paper; -+ -+import com.google.common.base.Objects; -+ -+import java.util.StringJoiner; -+ -+public class PaperSkinParts implements SkinParts { -+ -+ private final int raw; -+ -+ public PaperSkinParts(int raw) { -+ this.raw = raw; -+ } -+ -+ public boolean hasCapeEnabled() { -+ return (raw & 1) == 1; -+ } -+ -+ public boolean hasJacketEnabled() { -+ return (raw >> 1 & 1) == 1; -+ } -+ -+ public boolean hasLeftSleeveEnabled() { -+ return (raw >> 2 & 1) == 1; -+ } -+ -+ public boolean hasRightSleeveEnabled() { -+ return (raw >> 3 & 1) == 1; -+ } -+ -+ public boolean hasLeftPantsEnabled() { -+ return (raw >> 4 & 1) == 1; -+ } -+ -+ public boolean hasRightPantsEnabled() { -+ return (raw >> 5 & 1) == 1; -+ } -+ -+ public boolean hasHatsEnabled() { -+ return (raw >> 6 & 1) == 1; -+ } -+ -+ @Override -+ public int getRaw() { -+ return raw; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (this == o) return true; -+ if (o == null || getClass() != o.getClass()) return false; -+ PaperSkinParts that = (PaperSkinParts) o; -+ return raw == that.raw; -+ } -+ -+ @Override -+ public int hashCode() { -+ return Objects.hashCode(raw); -+ } -+ -+ @Override -+ public String toString() { -+ return new StringJoiner(", ", PaperSkinParts.class.getSimpleName() + "[", "]") -+ .add("raw=" + raw) -+ .add("cape=" + hasCapeEnabled()) -+ .add("jacket=" + hasJacketEnabled()) -+ .add("leftSleeve=" + hasLeftSleeveEnabled()) -+ .add("rightSleeve=" + hasRightSleeveEnabled()) -+ .add("leftPants=" + hasLeftPantsEnabled()) -+ .add("rightPants=" + hasRightPantsEnabled()) -+ .add("hats=" + hasHatsEnabled()) -+ .toString(); -+ } -+} -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index ba6dbbd56f5b0c2eb5566172e64fbf258f146ef0..d00d43697d7fc5b7fa162fd4e773f21fb5594087 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -418,7 +418,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - this.stats = server.getPlayerList().getPlayerStats(this); - this.advancements = server.getPlayerList().getPlayerAdvancements(this); - // this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); // Paper - Don't move existing players to world spawn -- this.updateOptions(clientOptions); -+ this.updateOptionsNoEvents(clientOptions); // Paper - don't call options events on login - this.object = null; - - // CraftBukkit start -@@ -2385,6 +2385,19 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - } - - public void updateOptions(ClientInformation clientOptions) { -+ // Paper start - settings event -+ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(this.getBukkitEntity(), Util.make(new java.util.IdentityHashMap<>(), map -> { -+ map.put(com.destroystokyo.paper.ClientOption.LOCALE, clientOptions.language()); -+ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, clientOptions.viewDistance()); -+ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(clientOptions.chatVisibility().name())); -+ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, clientOptions.chatColors()); -+ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, new com.destroystokyo.paper.PaperSkinParts(clientOptions.modelCustomisation())); -+ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, clientOptions.mainHand() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT); -+ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, clientOptions.textFilteringEnabled()); -+ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, clientOptions.allowsListing()); -+ map.put(com.destroystokyo.paper.ClientOption.PARTICLE_VISIBILITY, com.destroystokyo.paper.ClientOption.ParticleVisibility.valueOf(clientOptions.particleStatus().name())); -+ })).callEvent(); -+ // Paper end - settings event - // CraftBukkit start - if (this.getMainArm() != clientOptions.mainHand()) { - PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), this.getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT); -@@ -2395,6 +2408,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - this.server.server.getPluginManager().callEvent(event); - } - // CraftBukkit end -+ // Paper start - don't call options events on login -+ this.updateOptionsNoEvents(clientOptions); -+ } -+ public void updateOptionsNoEvents(ClientInformation clientOptions) { -+ // Paper end - this.language = clientOptions.language(); - this.adventure$locale = java.util.Objects.requireNonNullElse(net.kyori.adventure.translation.Translator.parseLocale(this.language), java.util.Locale.US); // Paper - this.requestedViewDistance = clientOptions.viewDistance(); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index e548834f2bd6e1e0a510a14040cc6aca63e2e6f5..589c78cf8acc8868be686123ac893421b4848239 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -658,6 +658,30 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message); - } - } -+ -+ @Override -+ public T getClientOption(com.destroystokyo.paper.ClientOption type) { -+ if (com.destroystokyo.paper.ClientOption.SKIN_PARTS == type) { -+ return type.getType().cast(new com.destroystokyo.paper.PaperSkinParts(this.getHandle().getEntityData().get(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION))); -+ } else if (com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED == type) { -+ return type.getType().cast(this.getHandle().canChatInColor()); -+ } else if (com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY == type) { -+ return type.getType().cast(com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(this.getHandle().getChatVisibility().name())); -+ } else if (com.destroystokyo.paper.ClientOption.LOCALE == type) { -+ return type.getType().cast(this.getLocale()); -+ } else if (com.destroystokyo.paper.ClientOption.MAIN_HAND == type) { -+ return type.getType().cast(this.getMainHand()); -+ } else if (com.destroystokyo.paper.ClientOption.VIEW_DISTANCE == type) { -+ return type.getType().cast(this.getClientViewDistance()); -+ } else if (com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED == type) { -+ return type.getType().cast(this.getHandle().isTextFilteringEnabled()); -+ } else if (com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS == type) { -+ return type.getType().cast(this.getHandle().allowsListing()); -+ } else if (com.destroystokyo.paper.ClientOption.PARTICLE_VISIBILITY == type) { -+ return type.getType().cast(com.destroystokyo.paper.ClientOption.ParticleVisibility.valueOf(this.getHandle().particleStatus.name())); -+ } -+ throw new RuntimeException("Unknown settings type"); -+ } - // Paper end - - @Override -diff --git a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..01e0936ea8ce5bcacafd9e89a1c0dfd2c172024d ---- /dev/null -+++ b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java -@@ -0,0 +1,25 @@ -+package io.papermc.paper.world; -+ -+import com.destroystokyo.paper.ClientOption; -+import net.minecraft.server.level.ParticleStatus; -+import net.minecraft.world.entity.player.ChatVisiblity; -+import org.junit.jupiter.api.Assertions; -+import org.junit.jupiter.api.Test; -+ -+public class TranslationKeyTest { -+ -+ @Test -+ public void testChatVisibilityKeys() { -+ for (ClientOption.ChatVisibility chatVisibility : ClientOption.ChatVisibility.values()) { -+ if (chatVisibility == ClientOption.ChatVisibility.UNKNOWN) continue; -+ Assertions.assertEquals(ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey(), chatVisibility + "'s translation key doesn't match"); -+ } -+ } -+ -+ @Test -+ public void testParticleVisibilityKeys() { -+ for (ClientOption.ParticleVisibility particleVisibility : ClientOption.ParticleVisibility.values()) { -+ Assertions.assertEquals(ParticleStatus.valueOf(particleVisibility.name()).getKey(), particleVisibility.translationKey(), particleVisibility + "'s translation key doesn't match"); -+ } -+ } -+} diff --git a/patches/server/0337-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch b/patches/server/0337-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch deleted file mode 100644 index 0db5556d5a..0000000000 --- a/patches/server/0337-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 18 Apr 2020 15:59:41 -0400 -Subject: [PATCH] Don't crash if player is attempted to be removed from - untracked chunk. - -I suspect it deals with teleporting as it uses players current x/y/z - -diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 6c2339d6a93172e25040c4868a3a47473a1f5336..f7c2c03749d6be25bf33afd61e1da120770b3432 100644 ---- a/src/main/java/net/minecraft/server/level/DistanceManager.java -+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -281,8 +281,8 @@ public abstract class DistanceManager { - ObjectSet objectset = (ObjectSet) this.playersPerChunk.get(i); - if (objectset == null) return; // CraftBukkit - SPIGOT-6208 - -- objectset.remove(player); -- if (objectset.isEmpty()) { -+ if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully -+ if (objectset == null || objectset.isEmpty()) { // Paper - this.playersPerChunk.remove(i); - this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); - this.playerTicketManager.update(i, Integer.MAX_VALUE, false); diff --git a/patches/server/0337-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch b/patches/server/0337-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch new file mode 100644 index 0000000000..c9d312ca37 --- /dev/null +++ b/patches/server/0337-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 19 Apr 2020 00:05:46 -0400 +Subject: [PATCH] Fire PlayerJoinEvent when Player is actually ready + +For years, plugin developers have had to delay many things they do +inside of the PlayerJoinEvent by 1 tick to make it actually work. + +This all boiled down to 1 reason why: The event fired before the +player was fully ready and joined to the world! + +Additionally, if that player logged out on a vehicle, the event +fired before the vehicle was even loaded, so that plugins had no +access to the vehicle during this event either. + +This change finally fixes this issue, fully preparing the player +into the world as a fully ready entity, vehicle included. + +There should be no plugins that break because of this change, but might +improve consistency with other plugins instead. + +For example, if 2 plugins listens to this event, and the first one +teleported the player in the event, then the 2nd plugin actually +would be getting a valid player! + +This was very non deterministic. This change will ensure every plugin +receives a deterministic result, and should no longer require 1 tick +delays anymore. + +== AT == +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 914e9e0af7533cbf487ea0413da447d5eb8d527b..69f54e812794b23e5f54606da86f71163f5f0bbe 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1299,6 +1299,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + return; + } + // Paper end - ignore and warn about illegal addEntity calls instead of crashing server ++ if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Paper - Fire PlayerJoinEvent when Player is actually ready; Delay adding to tracker until after list packets + if (!(entity instanceof EnderDragonPart)) { + EntityType entitytypes = entity.getType(); + int i = entitytypes.clientTrackingRange() * 16; +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 0efa13f8eff9458318f462e42fdbffe90e21d814..b1340a5021991d09a0f4a6ad4ce5d7389feb1175 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -315,6 +315,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + public double maxHealthCache; + public boolean joining = true; + public boolean sentListPacket = false; ++ public boolean supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready + public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent + // 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 d238dbd78fd18da46c703351cccc70c0b07622db..8239b9e2e1f5aa4f961aa40513f308f2fe44e7ef 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -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 + ++ // Paper start - Fire PlayerJoinEvent when Player is actually ready; correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks ++ player.supressTrackerForLogin = true; ++ worldserver1.addNewPlayer(player); ++ this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below worldserver.addPlayerJoin(entityplayer); ++ player.loadAndSpawnEnderpearls(optional); ++ player.loadAndSpawnParentVehicle(optional); ++ // Paper end - Fire PlayerJoinEvent when Player is actually ready + // CraftBukkit start + CraftPlayer bukkitPlayer = player.getBukkitEntity(); + +@@ -337,6 +344,8 @@ public abstract class PlayerList { + player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1))); + } + 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 + // CraftBukkit end + + player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn +@@ -352,8 +361,7 @@ public abstract class PlayerList { + worldserver1 = player.serverLevel(); // CraftBukkit - Update in case join event changed it + // CraftBukkit end + this.sendActivePlayerEffects(player); +- player.loadAndSpawnEnderpearls(optional); +- player.loadAndSpawnParentVehicle(optional); ++ // Paper - move loading pearls / parent vehicle up + player.initInventoryMenu(); + // CraftBukkit - Moved from above, added world + // Paper start - Configurable player collision; Add to collideRule team if needed diff --git a/patches/server/0338-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch b/patches/server/0338-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch deleted file mode 100644 index 42ec9120c0..0000000000 --- a/patches/server/0338-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 19 Apr 2020 00:05:46 -0400 -Subject: [PATCH] Fire PlayerJoinEvent when Player is actually ready - -For years, plugin developers have had to delay many things they do -inside of the PlayerJoinEvent by 1 tick to make it actually work. - -This all boiled down to 1 reason why: The event fired before the -player was fully ready and joined to the world! - -Additionally, if that player logged out on a vehicle, the event -fired before the vehicle was even loaded, so that plugins had no -access to the vehicle during this event either. - -This change finally fixes this issue, fully preparing the player -into the world as a fully ready entity, vehicle included. - -There should be no plugins that break because of this change, but might -improve consistency with other plugins instead. - -For example, if 2 plugins listens to this event, and the first one -teleported the player in the event, then the 2nd plugin actually -would be getting a valid player! - -This was very non deterministic. This change will ensure every plugin -receives a deterministic result, and should no longer require 1 tick -delays anymore. - -== AT == -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 914e9e0af7533cbf487ea0413da447d5eb8d527b..69f54e812794b23e5f54606da86f71163f5f0bbe 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1299,6 +1299,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - return; - } - // Paper end - ignore and warn about illegal addEntity calls instead of crashing server -+ if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Paper - Fire PlayerJoinEvent when Player is actually ready; Delay adding to tracker until after list packets - if (!(entity instanceof EnderDragonPart)) { - EntityType entitytypes = entity.getType(); - int i = entitytypes.clientTrackingRange() * 16; -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index d00d43697d7fc5b7fa162fd4e773f21fb5594087..07b1bc1a06ac1fec83ba76a73b3cc1bd8f560208 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -315,6 +315,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - public double maxHealthCache; - public boolean joining = true; - public boolean sentListPacket = false; -+ public boolean supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready - public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent - // 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 d238dbd78fd18da46c703351cccc70c0b07622db..8239b9e2e1f5aa4f961aa40513f308f2fe44e7ef 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -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 - -+ // Paper start - Fire PlayerJoinEvent when Player is actually ready; correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks -+ player.supressTrackerForLogin = true; -+ worldserver1.addNewPlayer(player); -+ this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below worldserver.addPlayerJoin(entityplayer); -+ player.loadAndSpawnEnderpearls(optional); -+ player.loadAndSpawnParentVehicle(optional); -+ // Paper end - Fire PlayerJoinEvent when Player is actually ready - // CraftBukkit start - CraftPlayer bukkitPlayer = player.getBukkitEntity(); - -@@ -337,6 +344,8 @@ public abstract class PlayerList { - player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1))); - } - 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 - // CraftBukkit end - - player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn -@@ -352,8 +361,7 @@ public abstract class PlayerList { - worldserver1 = player.serverLevel(); // CraftBukkit - Update in case join event changed it - // CraftBukkit end - this.sendActivePlayerEffects(player); -- player.loadAndSpawnEnderpearls(optional); -- player.loadAndSpawnParentVehicle(optional); -+ // Paper - move loading pearls / parent vehicle up - player.initInventoryMenu(); - // CraftBukkit - Moved from above, added world - // Paper start - Configurable player collision; Add to collideRule team if needed diff --git a/patches/server/0338-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch b/patches/server/0338-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch new file mode 100644 index 0000000000..c1f4591380 --- /dev/null +++ b/patches/server/0338-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch @@ -0,0 +1,119 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: 2277 <38501234+2277@users.noreply.github.com> +Date: Tue, 31 Mar 2020 10:33:55 +0100 +Subject: [PATCH] Move player to spawn point if spawn in unloaded world + +If the playerdata contains an invalid world (missing, unloaded, invalid, +etc.), spawn the player at the spawn point of the main world. + +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 8239b9e2e1f5aa4f961aa40513f308f2fe44e7ef..f11bea4618757ac8060098ab7a7a2642ff0a1ae4 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -197,6 +197,7 @@ public abstract class PlayerList { + } + + Optional optional = this.load(player); // CraftBukkit - decompile error ++ ResourceKey resourcekey = null; // Paper + // CraftBukkit start - Better rename detection + if (optional.isPresent()) { + CompoundTag nbttagcompound = optional.get(); +@@ -206,19 +207,47 @@ public abstract class PlayerList { + } + } + // CraftBukkit end +- ResourceKey resourcekey = (ResourceKey) optional.flatMap((nbttagcompound) -> { ++ // Paper start - move logic in Entity to here, to use bukkit supplied world UUID & reset to main world spawn if no valid world is found ++ boolean[] invalidPlayerWorld = {false}; ++ bukkitData: if (optional.isPresent()) { ++ // The main way for bukkit worlds to store the world is the world UUID despite mojang adding custom worlds ++ final org.bukkit.World bWorld; ++ if (optional.get().contains("WorldUUIDMost") && optional.get().contains("WorldUUIDLeast")) { ++ bWorld = org.bukkit.Bukkit.getServer().getWorld(new UUID(optional.get().getLong("WorldUUIDMost"), optional.get().getLong("WorldUUIDLeast"))); ++ } else if (optional.get().contains("world", net.minecraft.nbt.Tag.TAG_STRING)) { // Paper - legacy bukkit world name ++ bWorld = org.bukkit.Bukkit.getServer().getWorld(optional.get().getString("world")); ++ } else { ++ break bukkitData; // if neither of the bukkit data points exist, proceed to the vanilla migration section ++ } ++ if (bWorld != null) { ++ resourcekey = ((CraftWorld) bWorld).getHandle().dimension(); ++ } else { ++ resourcekey = Level.OVERWORLD; ++ invalidPlayerWorld[0] = true; ++ } ++ } ++ if (resourcekey == null) { // only run the vanilla logic if we haven't found a world from the bukkit data ++ // Below is the vanilla way of getting the dimension, this is for migration from vanilla servers ++ resourcekey = optional.flatMap((nbttagcompound) -> { ++ // Paper end + DataResult> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbttagcompound.get("Dimension"))); // CraftBukkit - decompile error + Logger logger = PlayerList.LOGGER; + + Objects.requireNonNull(logger); +- return dataresult.resultOrPartial(logger::error); +- }).orElse(player.serverLevel().dimension()); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD ++ // Paper start - reset to main world spawn if no valid world is found ++ final Optional> result = dataresult.resultOrPartial(logger::error); ++ invalidPlayerWorld[0] = result.isEmpty(); ++ return result; ++ }).orElse(Level.OVERWORLD); // Paper - revert to vanilla default main world, this isn't an "invalid world" since no player data existed ++ } ++ // Paper end + ServerLevel worldserver = this.server.getLevel(resourcekey); + ServerLevel worldserver1; + + if (worldserver == null) { + PlayerList.LOGGER.warn("Unknown respawn dimension {}, defaulting to overworld", resourcekey); + worldserver1 = this.server.overworld(); ++ invalidPlayerWorld[0] = true; // Paper - reset to main world if no world with parsed value is found + } else { + worldserver1 = worldserver; + } +@@ -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 ++ // Paper start - reset to main world spawn if first spawn or invalid world ++ } ++ 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); + } + // Paper end - Entity#getEntitySpawnReason +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index dcc6543f895c9bbf09301e64164873aa54c7b8b5..bccd5d2ef5cdc01d2785231d47ec17481f87f2cb 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2528,27 +2528,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + // CraftBukkit end + +- // CraftBukkit start - Reset world +- if (this instanceof ServerPlayer) { +- Server server = Bukkit.getServer(); +- org.bukkit.World bworld = null; +- +- // TODO: Remove World related checks, replaced with WorldUID +- String worldName = nbt.getString("world"); +- +- if (nbt.contains("WorldUUIDMost") && nbt.contains("WorldUUIDLeast")) { +- UUID uid = new UUID(nbt.getLong("WorldUUIDMost"), nbt.getLong("WorldUUIDLeast")); +- bworld = server.getWorld(uid); +- } else { +- bworld = server.getWorld(worldName); +- } +- +- if (bworld == null) { +- bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getLevel(Level.OVERWORLD).getWorld(); +- } +- +- ((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle()); +- } ++ // CraftBukkit start ++ // Paper - move world parsing/loading to PlayerList#placeNewPlayer + this.getBukkitEntity().readBukkitValues(nbt); + if (nbt.contains("Bukkit.invisible")) { + boolean bukkitInvisible = nbt.getBoolean("Bukkit.invisible"); diff --git a/patches/server/0339-Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/server/0339-Add-PlayerAttackEntityCooldownResetEvent.patch new file mode 100644 index 0000000000..4851f70e32 --- /dev/null +++ b/patches/server/0339-Add-PlayerAttackEntityCooldownResetEvent.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: nossr50 +Date: Thu, 26 Mar 2020 19:44:50 -0700 +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 77c924d5eecd8ee7fae0c6b49d46a6c91abc969a..52a1581a301a3aa481b4fe4afc978b0e426e814b 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -2364,7 +2364,17 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player) { +- ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); // Moved from EntityHuman in order to make the cooldown reset get called after the damage event is fired ++ // Paper start - PlayerAttackEntityCooldownResetEvent ++ //((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); // Moved from EntityHuman in order to make the cooldown reset get called after the damage event is fired ++ if (damagesource.getEntity() instanceof ServerPlayer) { ++ ServerPlayer player = (ServerPlayer) damagesource.getEntity(); ++ if (new com.destroystokyo.paper.event.player.PlayerAttackEntityCooldownResetEvent(player.getBukkitEntity(), this.getBukkitEntity(), player.getAttackStrengthScale(0F)).callEvent()) { ++ player.resetAttackStrengthTicker(); ++ } ++ } else { ++ ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); ++ } ++ // Paper end - PlayerAttackEntityCooldownResetEvent + } + + // Resistance diff --git a/patches/server/0339-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch b/patches/server/0339-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch deleted file mode 100644 index fcb4074808..0000000000 --- a/patches/server/0339-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 2277 <38501234+2277@users.noreply.github.com> -Date: Tue, 31 Mar 2020 10:33:55 +0100 -Subject: [PATCH] Move player to spawn point if spawn in unloaded world - -If the playerdata contains an invalid world (missing, unloaded, invalid, -etc.), spawn the player at the spawn point of the main world. - -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 8239b9e2e1f5aa4f961aa40513f308f2fe44e7ef..f11bea4618757ac8060098ab7a7a2642ff0a1ae4 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -197,6 +197,7 @@ public abstract class PlayerList { - } - - Optional optional = this.load(player); // CraftBukkit - decompile error -+ ResourceKey resourcekey = null; // Paper - // CraftBukkit start - Better rename detection - if (optional.isPresent()) { - CompoundTag nbttagcompound = optional.get(); -@@ -206,19 +207,47 @@ public abstract class PlayerList { - } - } - // CraftBukkit end -- ResourceKey resourcekey = (ResourceKey) optional.flatMap((nbttagcompound) -> { -+ // Paper start - move logic in Entity to here, to use bukkit supplied world UUID & reset to main world spawn if no valid world is found -+ boolean[] invalidPlayerWorld = {false}; -+ bukkitData: if (optional.isPresent()) { -+ // The main way for bukkit worlds to store the world is the world UUID despite mojang adding custom worlds -+ final org.bukkit.World bWorld; -+ if (optional.get().contains("WorldUUIDMost") && optional.get().contains("WorldUUIDLeast")) { -+ bWorld = org.bukkit.Bukkit.getServer().getWorld(new UUID(optional.get().getLong("WorldUUIDMost"), optional.get().getLong("WorldUUIDLeast"))); -+ } else if (optional.get().contains("world", net.minecraft.nbt.Tag.TAG_STRING)) { // Paper - legacy bukkit world name -+ bWorld = org.bukkit.Bukkit.getServer().getWorld(optional.get().getString("world")); -+ } else { -+ break bukkitData; // if neither of the bukkit data points exist, proceed to the vanilla migration section -+ } -+ if (bWorld != null) { -+ resourcekey = ((CraftWorld) bWorld).getHandle().dimension(); -+ } else { -+ resourcekey = Level.OVERWORLD; -+ invalidPlayerWorld[0] = true; -+ } -+ } -+ if (resourcekey == null) { // only run the vanilla logic if we haven't found a world from the bukkit data -+ // Below is the vanilla way of getting the dimension, this is for migration from vanilla servers -+ resourcekey = optional.flatMap((nbttagcompound) -> { -+ // Paper end - DataResult> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbttagcompound.get("Dimension"))); // CraftBukkit - decompile error - Logger logger = PlayerList.LOGGER; - - Objects.requireNonNull(logger); -- return dataresult.resultOrPartial(logger::error); -- }).orElse(player.serverLevel().dimension()); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD -+ // Paper start - reset to main world spawn if no valid world is found -+ final Optional> result = dataresult.resultOrPartial(logger::error); -+ invalidPlayerWorld[0] = result.isEmpty(); -+ return result; -+ }).orElse(Level.OVERWORLD); // Paper - revert to vanilla default main world, this isn't an "invalid world" since no player data existed -+ } -+ // Paper end - ServerLevel worldserver = this.server.getLevel(resourcekey); - ServerLevel worldserver1; - - if (worldserver == null) { - PlayerList.LOGGER.warn("Unknown respawn dimension {}, defaulting to overworld", resourcekey); - worldserver1 = this.server.overworld(); -+ invalidPlayerWorld[0] = true; // Paper - reset to main world if no world with parsed value is found - } else { - worldserver1 = worldserver; - } -@@ -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 -+ // Paper start - reset to main world spawn if first spawn or invalid world -+ } -+ 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); - } - // Paper end - Entity#getEntitySpawnReason -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index a330a603349f7f9d694cef66f67ba465e3110a1c..e5c280df931fc712e41f4decfeb2871b870d2e4a 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2528,27 +2528,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - // CraftBukkit end - -- // CraftBukkit start - Reset world -- if (this instanceof ServerPlayer) { -- Server server = Bukkit.getServer(); -- org.bukkit.World bworld = null; -- -- // TODO: Remove World related checks, replaced with WorldUID -- String worldName = nbt.getString("world"); -- -- if (nbt.contains("WorldUUIDMost") && nbt.contains("WorldUUIDLeast")) { -- UUID uid = new UUID(nbt.getLong("WorldUUIDMost"), nbt.getLong("WorldUUIDLeast")); -- bworld = server.getWorld(uid); -- } else { -- bworld = server.getWorld(worldName); -- } -- -- if (bworld == null) { -- bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getLevel(Level.OVERWORLD).getWorld(); -- } -- -- ((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle()); -- } -+ // CraftBukkit start -+ // Paper - move world parsing/loading to PlayerList#placeNewPlayer - this.getBukkitEntity().readBukkitValues(nbt); - if (nbt.contains("Bukkit.invisible")) { - boolean bukkitInvisible = nbt.getBoolean("Bukkit.invisible"); diff --git a/patches/server/0340-Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/server/0340-Add-PlayerAttackEntityCooldownResetEvent.patch deleted file mode 100644 index 4851f70e32..0000000000 --- a/patches/server/0340-Add-PlayerAttackEntityCooldownResetEvent.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: nossr50 -Date: Thu, 26 Mar 2020 19:44:50 -0700 -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 77c924d5eecd8ee7fae0c6b49d46a6c91abc969a..52a1581a301a3aa481b4fe4afc978b0e426e814b 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2364,7 +2364,17 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player) { -- ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); // Moved from EntityHuman in order to make the cooldown reset get called after the damage event is fired -+ // Paper start - PlayerAttackEntityCooldownResetEvent -+ //((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); // Moved from EntityHuman in order to make the cooldown reset get called after the damage event is fired -+ if (damagesource.getEntity() instanceof ServerPlayer) { -+ ServerPlayer player = (ServerPlayer) damagesource.getEntity(); -+ if (new com.destroystokyo.paper.event.player.PlayerAttackEntityCooldownResetEvent(player.getBukkitEntity(), this.getBukkitEntity(), player.getAttackStrengthScale(0F)).callEvent()) { -+ player.resetAttackStrengthTicker(); -+ } -+ } else { -+ ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); -+ } -+ // Paper end - PlayerAttackEntityCooldownResetEvent - } - - // Resistance diff --git a/patches/server/0340-Don-t-fire-BlockFade-on-worldgen-threads.patch b/patches/server/0340-Don-t-fire-BlockFade-on-worldgen-threads.patch new file mode 100644 index 0000000000..92b514b27e --- /dev/null +++ b/patches/server/0340-Don-t-fire-BlockFade-on-worldgen-threads.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 23 Apr 2020 01:36:39 -0400 +Subject: [PATCH] Don't fire BlockFade on worldgen threads + + +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 422e5750669457bea6e4b8de799d289e8e315a09..bd7835a8b470662b32cc28a4d8f777d4bb8dc60c 100644 +--- a/src/main/java/net/minecraft/world/level/block/FireBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java +@@ -108,6 +108,7 @@ public class FireBlock extends BaseFireBlock { + @Override + protected BlockState updateShape(BlockState state, LevelReader world, ScheduledTickAccess tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random) { + // CraftBukkit start ++ if (!(world instanceof ServerLevel)) return this.canSurvive(state, world, pos) ? (BlockState) this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)) : Blocks.AIR.defaultBlockState(); // Paper - don't fire events in world generation + if (!this.canSurvive(state, world, pos)) { + // Suppress during worldgen + if (!(world instanceof Level world1)) { +@@ -123,7 +124,7 @@ public class FireBlock extends BaseFireBlock { + return blockState.getHandle(); + } + } +- return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); ++ return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); // Paper - don't fire events in world generation; diff on change, see "don't fire events in world generation" + // CraftBukkit end + } + diff --git a/patches/server/0341-Add-phantom-creative-and-insomniac-controls.patch b/patches/server/0341-Add-phantom-creative-and-insomniac-controls.patch new file mode 100644 index 0000000000..3d6d830fae --- /dev/null +++ b/patches/server/0341-Add-phantom-creative-and-insomniac-controls.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 25 Apr 2020 15:13:41 -0500 +Subject: [PATCH] Add phantom creative and insomniac controls + + +diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java +index 3a4c1d4afddd7d8d1f43554a7a08855686cadf56..b8d57e25851dd7da905100dfd4022e4b99fd7f02 100644 +--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java ++++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java +@@ -27,6 +27,7 @@ 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 + + private EntitySelector() {} + // Paper start - Affects Spawning API +diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java +index 93013ca49e56f3ac47d67d0c48d87d53fca32a4f..1171a4e45bed0455b29b2cf012fbc2883b16d061 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java +@@ -550,6 +550,7 @@ public class Phantom extends FlyingMob implements Enemy { + Player entityhuman = (Player) iterator.next(); + + if (Phantom.this.canAttack(worldserver, entityhuman, TargetingConditions.DEFAULT)) { ++ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(entityhuman)) // Paper - Add phantom creative and insomniac controls + Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason + return true; + } +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 499b124f905ffa8e375efa354a3f2240997ddea5..7d407a7597f3ae576ac7e94bc2eb96d9dcd78dd3 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java +@@ -48,7 +48,7 @@ public class PhantomSpawner implements CustomSpawner { + while (iterator.hasNext()) { + ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + +- if (!entityplayer.isSpectator()) { ++ if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper - Add phantom creative and insomniac controls + BlockPos blockposition = entityplayer.blockPosition(); + + if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) { diff --git a/patches/server/0341-Don-t-fire-BlockFade-on-worldgen-threads.patch b/patches/server/0341-Don-t-fire-BlockFade-on-worldgen-threads.patch deleted file mode 100644 index 92b514b27e..0000000000 --- a/patches/server/0341-Don-t-fire-BlockFade-on-worldgen-threads.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 23 Apr 2020 01:36:39 -0400 -Subject: [PATCH] Don't fire BlockFade on worldgen threads - - -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 422e5750669457bea6e4b8de799d289e8e315a09..bd7835a8b470662b32cc28a4d8f777d4bb8dc60c 100644 ---- a/src/main/java/net/minecraft/world/level/block/FireBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java -@@ -108,6 +108,7 @@ public class FireBlock extends BaseFireBlock { - @Override - protected BlockState updateShape(BlockState state, LevelReader world, ScheduledTickAccess tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random) { - // CraftBukkit start -+ if (!(world instanceof ServerLevel)) return this.canSurvive(state, world, pos) ? (BlockState) this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)) : Blocks.AIR.defaultBlockState(); // Paper - don't fire events in world generation - if (!this.canSurvive(state, world, pos)) { - // Suppress during worldgen - if (!(world instanceof Level world1)) { -@@ -123,7 +124,7 @@ public class FireBlock extends BaseFireBlock { - return blockState.getHandle(); - } - } -- return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); -+ return this.getStateWithAge(world, pos, (Integer) state.getValue(FireBlock.AGE)); // Paper - don't fire events in world generation; diff on change, see "don't fire events in world generation" - // CraftBukkit end - } - diff --git a/patches/server/0342-Add-phantom-creative-and-insomniac-controls.patch b/patches/server/0342-Add-phantom-creative-and-insomniac-controls.patch deleted file mode 100644 index 3d6d830fae..0000000000 --- a/patches/server/0342-Add-phantom-creative-and-insomniac-controls.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 25 Apr 2020 15:13:41 -0500 -Subject: [PATCH] Add phantom creative and insomniac controls - - -diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java -index 3a4c1d4afddd7d8d1f43554a7a08855686cadf56..b8d57e25851dd7da905100dfd4022e4b99fd7f02 100644 ---- a/src/main/java/net/minecraft/world/entity/EntitySelector.java -+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java -@@ -27,6 +27,7 @@ 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 - - private EntitySelector() {} - // Paper start - Affects Spawning API -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index 93013ca49e56f3ac47d67d0c48d87d53fca32a4f..1171a4e45bed0455b29b2cf012fbc2883b16d061 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -550,6 +550,7 @@ public class Phantom extends FlyingMob implements Enemy { - Player entityhuman = (Player) iterator.next(); - - if (Phantom.this.canAttack(worldserver, entityhuman, TargetingConditions.DEFAULT)) { -+ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(entityhuman)) // Paper - Add phantom creative and insomniac controls - Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason - return true; - } -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 499b124f905ffa8e375efa354a3f2240997ddea5..7d407a7597f3ae576ac7e94bc2eb96d9dcd78dd3 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -@@ -48,7 +48,7 @@ public class PhantomSpawner implements CustomSpawner { - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); - -- if (!entityplayer.isSpectator()) { -+ if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper - Add phantom creative and insomniac controls - BlockPos blockposition = entityplayer.blockPosition(); - - if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) { diff --git a/patches/server/0342-Fix-item-duplication-and-teleport-issues.patch b/patches/server/0342-Fix-item-duplication-and-teleport-issues.patch new file mode 100644 index 0000000000..6121c288cf --- /dev/null +++ b/patches/server/0342-Fix-item-duplication-and-teleport-issues.patch @@ -0,0 +1,155 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 25 Apr 2020 06:46:35 -0400 +Subject: [PATCH] Fix item duplication and teleport issues + +This notably fixes the newest "Donkey Dupe", but also fixes a lot +of dupe bugs in general around nether portals and entity world transfer + +We also fix item duplication generically by anytime we clone an item +to drop it on the ground, destroy the source item. + +This avoid an itemstack ever existing twice in the world state pre +clean up stage. + +So even if something NEW comes up, it would be impossible to drop the +same item twice because the source was destroyed. + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index bccd5d2ef5cdc01d2785231d47ec17481f87f2cb..2dc87373d687c04f89c7a3b033c8a188ba415904 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2656,11 +2656,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } 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.asBukkitCopy(stack)); ++ ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later + return null; + } + // CraftBukkit end +- ItemEntity entityitem = new ItemEntity(world, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack); ++ 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(); + // CraftBukkit start +@@ -3493,6 +3494,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public Entity teleport(TeleportTransition teleportTarget) { + Level world = this.level(); + ++ // Paper start - Fix item duplication and teleport issues ++ if ((!this.isAlive() || !this.valid) && (teleportTarget.newLevel() != world)) { ++ LOGGER.warn("Illegal Entity Teleport " + this + " to " + teleportTarget.newLevel() + ":" + teleportTarget.position(), new Throwable()); ++ return null; ++ } ++ // Paper end - Fix item duplication and teleport issues + if (world instanceof ServerLevel worldserver) { + if (!this.isRemoved()) { + // CraftBukkit start +@@ -3581,6 +3588,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + gameprofilerfiller.pop(); + return null; + } else { ++ // Paper start - Fix item duplication and teleport issues ++ if (this instanceof Leashable leashable) { ++ leashable.dropLeash(); // Paper drop lead ++ } ++ // Paper end - Fix item duplication and teleport issues + entity.restoreFrom(this); + this.removeAfterChangingDimensions(); + // CraftBukkit start - Forward the CraftEntity to the new entity +@@ -3693,6 +3705,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public boolean canTeleport(Level from, Level to) { ++ if (!this.isAlive() || !this.valid) return false; // Paper - Fix item duplication and teleport issues + if (from.dimension() == Level.END && to.dimension() == Level.OVERWORLD) { + 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 52a1581a301a3aa481b4fe4afc978b0e426e814b..cd54ab0fed100bf1dd7261185ef0f4e5d4433aa7 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -1776,9 +1776,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()) { +- if (entityliving != null) { +- entityliving.awardKillScore(this, damageSource); +- } ++ //if (entityliving != null) { // Paper - Fix item duplication and teleport issues; moved to be run earlier in #dropAllDeathLoot before destroying the drop items in CraftEventFactory#callEntityDeathEvent ++ // entityliving.awardKillScore(this, damageSource); ++ //} + // Paper start - clear equipment if event is not cancelled + if (this instanceof Mob) { + for (EquipmentSlot slot : this.clearedEquipmentSlots) { +@@ -1872,8 +1872,13 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.dropCustomDeathLoot(world, damageSource, flag); + this.clearEquipmentSlots = prev; // Paper + } +- // CraftBukkit start - Call death event +- org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops); // Paper ++ // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops, () -> { ++ final LivingEntity entityliving = this.getKillCredit(); ++ if (entityliving != null) { ++ entityliving.awardKillScore(this, damageSource); ++ } ++ }); // Paper end + this.postDeathDropItems(deathEvent); // Paper + this.drops = new ArrayList<>(); + // CraftBukkit end +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 e20565cf256aacd012a1722c5ebbf9016bc82e42..59fbfe8de2dc5ec020dd61a5e446b0b6f67d76e4 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java +@@ -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.asBukkitCopy(itemstack)); // CraftBukkit - add to drops ++ 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.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.asBukkitCopy(itemstack)); // CraftBukkit - add to drops ++ 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.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 74f33aeb6193080446ebbcc5242d95c3b1c97823..f482fc14e171129f9fa60113b1223b2db79ec6ec 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -903,6 +903,11 @@ public class CraftEventFactory { + } + + public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops) { ++ // 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) { ++ // Paper end + CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity(); + CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource); + CraftWorld world = (CraftWorld) entity.getWorld(); +@@ -917,11 +922,13 @@ public class CraftEventFactory { + playDeathSound(victim, event); + // Paper end + victim.expToDrop = event.getDroppedExp(); ++ lootCheck.run(); // Paper - advancement triggers before destroying items + + for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { + if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue; + +- world.dropItem(entity.getLocation(), stack); ++ world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS ++ 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; diff --git a/patches/server/0343-Fix-item-duplication-and-teleport-issues.patch b/patches/server/0343-Fix-item-duplication-and-teleport-issues.patch deleted file mode 100644 index 7f2cff96c8..0000000000 --- a/patches/server/0343-Fix-item-duplication-and-teleport-issues.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 25 Apr 2020 06:46:35 -0400 -Subject: [PATCH] Fix item duplication and teleport issues - -This notably fixes the newest "Donkey Dupe", but also fixes a lot -of dupe bugs in general around nether portals and entity world transfer - -We also fix item duplication generically by anytime we clone an item -to drop it on the ground, destroy the source item. - -This avoid an itemstack ever existing twice in the world state pre -clean up stage. - -So even if something NEW comes up, it would be impossible to drop the -same item twice because the source was destroyed. - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index e5c280df931fc712e41f4decfeb2871b870d2e4a..c48f634fe80919cb1c2c4d2c1fd647dc63c87749 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2656,11 +2656,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } 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.asBukkitCopy(stack)); -+ ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later - return null; - } - // CraftBukkit end -- ItemEntity entityitem = new ItemEntity(world, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack); -+ 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(); - // CraftBukkit start -@@ -3493,6 +3494,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public Entity teleport(TeleportTransition teleportTarget) { - Level world = this.level(); - -+ // Paper start - Fix item duplication and teleport issues -+ if ((!this.isAlive() || !this.valid) && (teleportTarget.newLevel() != world)) { -+ LOGGER.warn("Illegal Entity Teleport " + this + " to " + teleportTarget.newLevel() + ":" + teleportTarget.position(), new Throwable()); -+ return null; -+ } -+ // Paper end - Fix item duplication and teleport issues - if (world instanceof ServerLevel worldserver) { - if (!this.isRemoved()) { - // CraftBukkit start -@@ -3581,6 +3588,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - gameprofilerfiller.pop(); - return null; - } else { -+ // Paper start - Fix item duplication and teleport issues -+ if (this instanceof Leashable leashable) { -+ leashable.dropLeash(); // Paper drop lead -+ } -+ // Paper end - Fix item duplication and teleport issues - entity.restoreFrom(this); - this.removeAfterChangingDimensions(); - // CraftBukkit start - Forward the CraftEntity to the new entity -@@ -3693,6 +3705,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public boolean canTeleport(Level from, Level to) { -+ if (!this.isAlive() || !this.valid) return false; // Paper - Fix item duplication and teleport issues - if (from.dimension() == Level.END && to.dimension() == Level.OVERWORLD) { - 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 52a1581a301a3aa481b4fe4afc978b0e426e814b..cd54ab0fed100bf1dd7261185ef0f4e5d4433aa7 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1776,9 +1776,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()) { -- if (entityliving != null) { -- entityliving.awardKillScore(this, damageSource); -- } -+ //if (entityliving != null) { // Paper - Fix item duplication and teleport issues; moved to be run earlier in #dropAllDeathLoot before destroying the drop items in CraftEventFactory#callEntityDeathEvent -+ // entityliving.awardKillScore(this, damageSource); -+ //} - // Paper start - clear equipment if event is not cancelled - if (this instanceof Mob) { - for (EquipmentSlot slot : this.clearedEquipmentSlots) { -@@ -1872,8 +1872,13 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.dropCustomDeathLoot(world, damageSource, flag); - this.clearEquipmentSlots = prev; // Paper - } -- // CraftBukkit start - Call death event -- org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops); // Paper -+ // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment -+ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops, () -> { -+ final LivingEntity entityliving = this.getKillCredit(); -+ if (entityliving != null) { -+ entityliving.awardKillScore(this, damageSource); -+ } -+ }); // Paper end - this.postDeathDropItems(deathEvent); // Paper - this.drops = new ArrayList<>(); - // CraftBukkit end -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 e20565cf256aacd012a1722c5ebbf9016bc82e42..59fbfe8de2dc5ec020dd61a5e446b0b6f67d76e4 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -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.asBukkitCopy(itemstack)); // CraftBukkit - add to drops -+ 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.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.asBukkitCopy(itemstack)); // CraftBukkit - add to drops -+ 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.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 74f33aeb6193080446ebbcc5242d95c3b1c97823..f482fc14e171129f9fa60113b1223b2db79ec6ec 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -903,6 +903,11 @@ public class CraftEventFactory { - } - - public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List drops) { -+ // 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) { -+ // Paper end - CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity(); - CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource); - CraftWorld world = (CraftWorld) entity.getWorld(); -@@ -917,11 +922,13 @@ public class CraftEventFactory { - playDeathSound(victim, event); - // Paper end - victim.expToDrop = event.getDroppedExp(); -+ lootCheck.run(); // Paper - advancement triggers before destroying items - - for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { - if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue; - -- world.dropItem(entity.getLocation(), stack); -+ world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS -+ 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; diff --git a/patches/server/0343-Villager-Restocks-API.patch b/patches/server/0343-Villager-Restocks-API.patch new file mode 100644 index 0000000000..4ad766705c --- /dev/null +++ b/patches/server/0343-Villager-Restocks-API.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: zbk +Date: Sun, 26 Apr 2020 23:49:01 -0400 +Subject: [PATCH] Villager Restocks API + +== AT == +public net.minecraft.world.entity.npc.Villager numberOfRestocksToday + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +index 1a7b666f9795e72022a60d14bfd405ae3165e292..ded319d10a5907b96abfd5620036b66a9aa3b3f7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +@@ -90,6 +90,18 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { + this.getHandle().setVillagerXp(experience); + } + ++ // Paper start ++ @Override ++ public int getRestocksToday() { ++ return getHandle().numberOfRestocksToday; ++ } ++ ++ @Override ++ public void setRestocksToday(int restocksToday) { ++ getHandle().numberOfRestocksToday = restocksToday; ++ } ++ // Paper end ++ + @Override + public boolean sleep(Location location) { + Preconditions.checkArgument(location != null, "Location cannot be null"); diff --git a/patches/server/0344-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch b/patches/server/0344-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch new file mode 100644 index 0000000000..e423cfabe1 --- /dev/null +++ b/patches/server/0344-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 4 May 2020 01:08:56 -0400 +Subject: [PATCH] Set cap on JDK per-thread native byte buffer cache + +See: https://www.evanjones.ca/java-bytebuffer-leak.html + +This is potentially a source of lots of native memory usage. + +We are clearly seeing native usage upwards to 1-4GB which doesn't make sense. + +Region File usage fixed in previous patch should of tecnically only been somewhat +temporary until GC finally gets it some time later, but between all the various +plugins doing IO on various threads, this hidden detail of the JDK could be +keeping long lived large direct buffers in cache. + +Set system properly at server startup if not set already to help protect from this. + +diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java +index d84afe883d5af0800b5c85649a691bc811c2e357..dd2e1ff287ccb86b7ba714604672d2f3d7ef8c61 100644 +--- a/src/main/java/org/bukkit/craftbukkit/Main.java ++++ b/src/main/java/org/bukkit/craftbukkit/Main.java +@@ -27,6 +27,7 @@ public class Main { + } + // Paper end + // Todo: Installation script ++ if (System.getProperty("jdk.nio.maxCachedBufferSize") == null) System.setProperty("jdk.nio.maxCachedBufferSize", "262144"); // Paper - cap per-thread NIO cache size; https://www.evanjones.ca/java-bytebuffer-leak.html + OptionParser parser = new OptionParser() { + { + this.acceptsAll(Main.asList("?", "help"), "Show the help"); diff --git a/patches/server/0344-Villager-Restocks-API.patch b/patches/server/0344-Villager-Restocks-API.patch deleted file mode 100644 index 4ad766705c..0000000000 --- a/patches/server/0344-Villager-Restocks-API.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: zbk -Date: Sun, 26 Apr 2020 23:49:01 -0400 -Subject: [PATCH] Villager Restocks API - -== AT == -public net.minecraft.world.entity.npc.Villager numberOfRestocksToday - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -index 1a7b666f9795e72022a60d14bfd405ae3165e292..ded319d10a5907b96abfd5620036b66a9aa3b3f7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -@@ -90,6 +90,18 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { - this.getHandle().setVillagerXp(experience); - } - -+ // Paper start -+ @Override -+ public int getRestocksToday() { -+ return getHandle().numberOfRestocksToday; -+ } -+ -+ @Override -+ public void setRestocksToday(int restocksToday) { -+ getHandle().numberOfRestocksToday = restocksToday; -+ } -+ // Paper end -+ - @Override - public boolean sleep(Location location) { - Preconditions.checkArgument(location != null, "Location cannot be null"); diff --git a/patches/server/0345-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch b/patches/server/0345-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch deleted file mode 100644 index e423cfabe1..0000000000 --- a/patches/server/0345-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 4 May 2020 01:08:56 -0400 -Subject: [PATCH] Set cap on JDK per-thread native byte buffer cache - -See: https://www.evanjones.ca/java-bytebuffer-leak.html - -This is potentially a source of lots of native memory usage. - -We are clearly seeing native usage upwards to 1-4GB which doesn't make sense. - -Region File usage fixed in previous patch should of tecnically only been somewhat -temporary until GC finally gets it some time later, but between all the various -plugins doing IO on various threads, this hidden detail of the JDK could be -keeping long lived large direct buffers in cache. - -Set system properly at server startup if not set already to help protect from this. - -diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index d84afe883d5af0800b5c85649a691bc811c2e357..dd2e1ff287ccb86b7ba714604672d2f3d7ef8c61 100644 ---- a/src/main/java/org/bukkit/craftbukkit/Main.java -+++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -27,6 +27,7 @@ public class Main { - } - // Paper end - // Todo: Installation script -+ if (System.getProperty("jdk.nio.maxCachedBufferSize") == null) System.setProperty("jdk.nio.maxCachedBufferSize", "262144"); // Paper - cap per-thread NIO cache size; https://www.evanjones.ca/java-bytebuffer-leak.html - OptionParser parser = new OptionParser() { - { - this.acceptsAll(Main.asList("?", "help"), "Show the help"); diff --git a/patches/server/0345-misc-debugging-dumps.patch b/patches/server/0345-misc-debugging-dumps.patch new file mode 100644 index 0000000000..fc898c3359 --- /dev/null +++ b/patches/server/0345-misc-debugging-dumps.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Thu, 18 Feb 2021 20:23:28 +0000 +Subject: [PATCH] misc debugging dumps + + +diff --git a/src/main/java/io/papermc/paper/util/TraceUtil.java b/src/main/java/io/papermc/paper/util/TraceUtil.java +new file mode 100644 +index 0000000000000000000000000000000000000000..479bb92d159f33c54c2d9c39d8a63aa9e74d95b9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/TraceUtil.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.util; ++ ++import org.bukkit.Bukkit; ++ ++public final class TraceUtil { ++ ++ public static void dumpTraceForThread(Thread thread, String reason) { ++ Bukkit.getLogger().warning(thread.getName() + ": " + reason); ++ StackTraceElement[] trace = StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace()); ++ for (StackTraceElement traceElement : trace) { ++ Bukkit.getLogger().warning("\tat " + traceElement); ++ } ++ } ++ ++ public static void dumpTraceForThread(String reason) { ++ final Throwable thr = new Throwable(reason); ++ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr); ++ thr.printStackTrace(); ++ } ++ ++ public static void printStackTrace(Throwable thr) { ++ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr); ++ thr.printStackTrace(); ++ } ++} +diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java +index 642d5c6849debc5a266605b0df30d55222339438..b34abf66c7dc756e88e08637af976f7794144d06 100644 +--- a/src/main/java/net/minecraft/commands/Commands.java ++++ b/src/main/java/net/minecraft/commands/Commands.java +@@ -345,7 +345,7 @@ public class Commands { + } catch (Exception exception) { + MutableComponent ichatmutablecomponent = Component.literal(exception.getMessage() == null ? exception.getClass().getName() : exception.getMessage()); + +- if (Commands.LOGGER.isDebugEnabled()) { ++ if (commandlistenerwrapper.getServer().isDebugging() || Commands.LOGGER.isDebugEnabled()) { // Paper - Debugging + Commands.LOGGER.error("Command exception: /{}", s, exception); + 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 e1a15f3721e3c661be0185d65073a39f293f0589..8e205796d0c9abbf01bf6ec191e2dfc7b972a0dd 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -929,6 +929,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Tue, 3 Mar 2020 05:26:40 +0000 +Subject: [PATCH] Prevent teleporting dead entities + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 859aa632d063cdd033b99c63b6f3e8837356ed45..517c215d47737c551125dec785de2896560f4cb0 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1625,6 +1625,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + + public void internalTeleport(PositionMoveRotation positionmoverotation, Set set) { ++ // Paper start - Prevent teleporting dead entities ++ if (player.isRemoved()) { ++ LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName()); ++ if (server.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Attempt to teleport removed player"); ++ return; ++ } ++ // Paper end - Prevent teleporting dead entities + if (Float.isNaN(positionmoverotation.yRot())) { + positionmoverotation = new PositionMoveRotation(positionmoverotation.position(), positionmoverotation.deltaMovement(), 0, positionmoverotation.xRot()); + } diff --git a/patches/server/0346-misc-debugging-dumps.patch b/patches/server/0346-misc-debugging-dumps.patch deleted file mode 100644 index fc898c3359..0000000000 --- a/patches/server/0346-misc-debugging-dumps.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Thu, 18 Feb 2021 20:23:28 +0000 -Subject: [PATCH] misc debugging dumps - - -diff --git a/src/main/java/io/papermc/paper/util/TraceUtil.java b/src/main/java/io/papermc/paper/util/TraceUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..479bb92d159f33c54c2d9c39d8a63aa9e74d95b9 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/util/TraceUtil.java -@@ -0,0 +1,25 @@ -+package io.papermc.paper.util; -+ -+import org.bukkit.Bukkit; -+ -+public final class TraceUtil { -+ -+ public static void dumpTraceForThread(Thread thread, String reason) { -+ Bukkit.getLogger().warning(thread.getName() + ": " + reason); -+ StackTraceElement[] trace = StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace()); -+ for (StackTraceElement traceElement : trace) { -+ Bukkit.getLogger().warning("\tat " + traceElement); -+ } -+ } -+ -+ public static void dumpTraceForThread(String reason) { -+ final Throwable thr = new Throwable(reason); -+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr); -+ thr.printStackTrace(); -+ } -+ -+ public static void printStackTrace(Throwable thr) { -+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr); -+ thr.printStackTrace(); -+ } -+} -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 642d5c6849debc5a266605b0df30d55222339438..b34abf66c7dc756e88e08637af976f7794144d06 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -345,7 +345,7 @@ public class Commands { - } catch (Exception exception) { - MutableComponent ichatmutablecomponent = Component.literal(exception.getMessage() == null ? exception.getClass().getName() : exception.getMessage()); - -- if (Commands.LOGGER.isDebugEnabled()) { -+ if (commandlistenerwrapper.getServer().isDebugging() || Commands.LOGGER.isDebugEnabled()) { // Paper - Debugging - Commands.LOGGER.error("Command exception: /{}", s, exception); - 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 e1a15f3721e3c661be0185d65073a39f293f0589..8e205796d0c9abbf01bf6ec191e2dfc7b972a0dd 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -929,6 +929,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Fri, 3 Jan 2020 16:26:19 +0100 +Subject: [PATCH] Implement Mob Goal API + + +diff --git a/build.gradle.kts b/build.gradle.kts +index d5ad109d2deb4fe756924ebaac4091017beb6b99..cc0a3c29aeb67e486fb75c1d6cc280192421c7cd 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -55,6 +55,7 @@ dependencies { + runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") + runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") + ++ testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test + testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") + testImplementation("org.junit.platform:junit-platform-suite-engine:1.10.0") + testImplementation("org.hamcrest:hamcrest:2.2") +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +new file mode 100644 +index 0000000000000000000000000000000000000000..99d0118061233eced90ca5aed2eb5ff0b188837b +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +@@ -0,0 +1,379 @@ ++package com.destroystokyo.paper.entity.ai; ++ ++import com.destroystokyo.paper.entity.RangedEntity; ++import com.google.common.collect.BiMap; ++import com.google.common.collect.HashBiMap; ++import io.papermc.paper.util.ObfHelper; ++import java.lang.reflect.Constructor; ++import java.util.EnumSet; ++import java.util.HashMap; ++import java.util.HashSet; ++import java.util.Map; ++import java.util.Set; ++import net.minecraft.world.entity.FlyingMob; ++import net.minecraft.world.entity.PathfinderMob; ++import net.minecraft.world.entity.TamableAnimal; ++import net.minecraft.world.entity.ai.goal.Goal; ++import net.minecraft.world.entity.ambient.AmbientCreature; ++import net.minecraft.world.entity.animal.AbstractFish; ++import net.minecraft.world.entity.animal.AbstractGolem; ++import net.minecraft.world.entity.animal.AbstractSchoolingFish; ++import net.minecraft.world.entity.animal.Animal; ++import net.minecraft.world.entity.animal.Pufferfish; ++import net.minecraft.world.entity.animal.ShoulderRidingEntity; ++import net.minecraft.world.entity.animal.SnowGolem; ++import net.minecraft.world.entity.animal.WaterAnimal; ++import net.minecraft.world.entity.animal.camel.Camel; ++import net.minecraft.world.entity.animal.horse.AbstractChestedHorse; ++import net.minecraft.world.entity.boss.wither.WitherBoss; ++import net.minecraft.world.entity.monster.AbstractIllager; ++import net.minecraft.world.entity.monster.EnderMan; ++import net.minecraft.world.entity.monster.PatrollingMonster; ++import net.minecraft.world.entity.monster.RangedAttackMob; ++import net.minecraft.world.entity.monster.SpellcasterIllager; ++import net.minecraft.world.entity.monster.ZombifiedPiglin; ++import net.minecraft.world.entity.monster.breeze.Breeze; ++import net.minecraft.world.entity.monster.piglin.AbstractPiglin; ++import org.bukkit.NamespacedKey; ++import org.bukkit.entity.AbstractHorse; ++import org.bukkit.entity.AbstractSkeleton; ++import org.bukkit.entity.AbstractVillager; ++import org.bukkit.entity.Ageable; ++import org.bukkit.entity.Ambient; ++import org.bukkit.entity.Animals; ++import org.bukkit.entity.Bat; ++import org.bukkit.entity.Bee; ++import org.bukkit.entity.Blaze; ++import org.bukkit.entity.Cat; ++import org.bukkit.entity.CaveSpider; ++import org.bukkit.entity.ChestedHorse; ++import org.bukkit.entity.Chicken; ++import org.bukkit.entity.Cod; ++import org.bukkit.entity.Cow; ++import org.bukkit.entity.Creature; ++import org.bukkit.entity.Creeper; ++import org.bukkit.entity.Dolphin; ++import org.bukkit.entity.Donkey; ++import org.bukkit.entity.Drowned; ++import org.bukkit.entity.ElderGuardian; ++import org.bukkit.entity.EnderDragon; ++import org.bukkit.entity.Enderman; ++import org.bukkit.entity.Endermite; ++import org.bukkit.entity.Evoker; ++import org.bukkit.entity.Fish; ++import org.bukkit.entity.Flying; ++import org.bukkit.entity.Fox; ++import org.bukkit.entity.Ghast; ++import org.bukkit.entity.Giant; ++import org.bukkit.entity.Golem; ++import org.bukkit.entity.Guardian; ++import org.bukkit.entity.Hoglin; ++import org.bukkit.entity.Horse; ++import org.bukkit.entity.Husk; ++import org.bukkit.entity.Illager; ++import org.bukkit.entity.Illusioner; ++import org.bukkit.entity.IronGolem; ++import org.bukkit.entity.Llama; ++import org.bukkit.entity.MagmaCube; ++import org.bukkit.entity.Mob; ++import org.bukkit.entity.Monster; ++import org.bukkit.entity.Mule; ++import org.bukkit.entity.MushroomCow; ++import org.bukkit.entity.Ocelot; ++import org.bukkit.entity.Panda; ++import org.bukkit.entity.Parrot; ++import org.bukkit.entity.Phantom; ++import org.bukkit.entity.Pig; ++import org.bukkit.entity.PigZombie; ++import org.bukkit.entity.Piglin; ++import org.bukkit.entity.PiglinAbstract; ++import org.bukkit.entity.PiglinBrute; ++import org.bukkit.entity.Pillager; ++import org.bukkit.entity.PolarBear; ++import org.bukkit.entity.PufferFish; ++import org.bukkit.entity.Rabbit; ++import org.bukkit.entity.Raider; ++import org.bukkit.entity.Ravager; ++import org.bukkit.entity.Salmon; ++import org.bukkit.entity.Sheep; ++import org.bukkit.entity.Shulker; ++import org.bukkit.entity.Silverfish; ++import org.bukkit.entity.Skeleton; ++import org.bukkit.entity.SkeletonHorse; ++import org.bukkit.entity.Slime; ++import org.bukkit.entity.Snowman; ++import org.bukkit.entity.Spellcaster; ++import org.bukkit.entity.Spider; ++import org.bukkit.entity.Squid; ++import org.bukkit.entity.Stray; ++import org.bukkit.entity.Strider; ++import org.bukkit.entity.Tameable; ++import org.bukkit.entity.TraderLlama; ++import org.bukkit.entity.TropicalFish; ++import org.bukkit.entity.Turtle; ++import org.bukkit.entity.Vex; ++import org.bukkit.entity.Villager; ++import org.bukkit.entity.Vindicator; ++import org.bukkit.entity.WanderingTrader; ++import org.bukkit.entity.WaterMob; ++import org.bukkit.entity.Witch; ++import org.bukkit.entity.Wither; ++import org.bukkit.entity.WitherSkeleton; ++import org.bukkit.entity.Wolf; ++import org.bukkit.entity.Zoglin; ++import org.bukkit.entity.Zombie; ++import org.bukkit.entity.ZombieHorse; ++import org.bukkit.entity.ZombieVillager; ++ ++public class MobGoalHelper { ++ ++ private static final BiMap deobfuscationMap = HashBiMap.create(); ++ private static final Map, Class> entityClassCache = new HashMap<>(); ++ private static final Map, Class> bukkitMap = new HashMap<>(); ++ ++ static final Set ignored = new HashSet<>(); ++ ++ static { ++ // TODO these kinda should be checked on each release, in case obfuscation changes ++ deobfuscationMap.put("abstract_skeleton_1", "abstract_skeleton_melee"); ++ ++ ignored.add("goal_selector_1"); ++ ignored.add("goal_selector_2"); ++ ignored.add("selector_1"); ++ ignored.add("selector_2"); ++ ignored.add("wrapped"); ++ ++ bukkitMap.put(net.minecraft.world.entity.Mob.class, Mob.class); ++ bukkitMap.put(net.minecraft.world.entity.AgeableMob.class, Ageable.class); ++ bukkitMap.put(AmbientCreature.class, Ambient.class); ++ bukkitMap.put(Animal.class, Animals.class); ++ bukkitMap.put(net.minecraft.world.entity.ambient.Bat.class, Bat.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Bee.class, Bee.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Blaze.class, Blaze.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Cat.class, Cat.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.CaveSpider.class, CaveSpider.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Chicken.class, Chicken.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Cod.class, Cod.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Cow.class, Cow.class); ++ bukkitMap.put(PathfinderMob.class, Creature.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Creeper.class, Creeper.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Dolphin.class, Dolphin.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Drowned.class, Drowned.class); ++ bukkitMap.put(net.minecraft.world.entity.boss.enderdragon.EnderDragon.class, EnderDragon.class); ++ bukkitMap.put(EnderMan.class, Enderman.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Endermite.class, Endermite.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Evoker.class, Evoker.class); ++ bukkitMap.put(AbstractFish.class, Fish.class); ++ bukkitMap.put(AbstractSchoolingFish.class, Fish.class); // close enough ++ bukkitMap.put(FlyingMob.class, Flying.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Fox.class, Fox.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Ghast.class, Ghast.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Giant.class, Giant.class); ++ bukkitMap.put(AbstractGolem.class, Golem.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Guardian.class, Guardian.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.ElderGuardian.class, ElderGuardian.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.horse.Horse.class, Horse.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.horse.AbstractHorse.class, AbstractHorse.class); ++ bukkitMap.put(AbstractChestedHorse.class, ChestedHorse.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.horse.Donkey.class, Donkey.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.horse.Mule.class, Mule.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.horse.SkeletonHorse.class, SkeletonHorse.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.horse.ZombieHorse.class, ZombieHorse.class); ++ bukkitMap.put(Camel.class, org.bukkit.entity.Camel.class); ++ bukkitMap.put(AbstractIllager.class, Illager.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Illusioner.class, Illusioner.class); ++ bukkitMap.put(SpellcasterIllager.class, Spellcaster.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.IronGolem.class, IronGolem.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.horse.Llama.class, Llama.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.horse.TraderLlama.class, TraderLlama.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.MagmaCube.class, MagmaCube.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Monster.class, Monster.class); ++ bukkitMap.put(PatrollingMonster.class, Raider.class); // close enough ++ bukkitMap.put(net.minecraft.world.entity.animal.MushroomCow.class, MushroomCow.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Ocelot.class, Ocelot.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Panda.class, Panda.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Parrot.class, Parrot.class); ++ bukkitMap.put(ShoulderRidingEntity.class, Parrot.class); // close enough ++ bukkitMap.put(net.minecraft.world.entity.monster.Phantom.class, Phantom.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Pig.class, Pig.class); ++ bukkitMap.put(ZombifiedPiglin.class, PigZombie.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Pillager.class, Pillager.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.PolarBear.class, PolarBear.class); ++ bukkitMap.put(Pufferfish.class, PufferFish.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Rabbit.class, Rabbit.class); ++ bukkitMap.put(net.minecraft.world.entity.raid.Raider.class, Raider.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Ravager.class, Ravager.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Salmon.class, Salmon.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Sheep.class, Sheep.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Shulker.class, Shulker.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Silverfish.class, Silverfish.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Skeleton.class, Skeleton.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.AbstractSkeleton.class, AbstractSkeleton.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Stray.class, Stray.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.WitherSkeleton.class, WitherSkeleton.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Slime.class, Slime.class); ++ bukkitMap.put(SnowGolem.class, Snowman.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Spider.class, Spider.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Squid.class, Squid.class); ++ bukkitMap.put(TamableAnimal.class, Tameable.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.TropicalFish.class, TropicalFish.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Turtle.class, Turtle.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Vex.class, Vex.class); ++ bukkitMap.put(net.minecraft.world.entity.npc.Villager.class, Villager.class); ++ bukkitMap.put(net.minecraft.world.entity.npc.AbstractVillager.class, AbstractVillager.class); ++ bukkitMap.put(net.minecraft.world.entity.npc.WanderingTrader.class, WanderingTrader.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Vindicator.class, Vindicator.class); ++ bukkitMap.put(WaterAnimal.class, WaterMob.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Witch.class, Witch.class); ++ bukkitMap.put(WitherBoss.class, Wither.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.Wolf.class, Wolf.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Zombie.class, Zombie.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Husk.class, Husk.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.ZombieVillager.class, ZombieVillager.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.hoglin.Hoglin.class, Hoglin.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.piglin.Piglin.class, Piglin.class); ++ bukkitMap.put(AbstractPiglin.class, PiglinAbstract.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.piglin.PiglinBrute.class, PiglinBrute.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Strider.class, Strider.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Zoglin.class, Zoglin.class); ++ bukkitMap.put(net.minecraft.world.entity.GlowSquid.class, org.bukkit.entity.GlowSquid.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.axolotl.Axolotl.class, org.bukkit.entity.Axolotl.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.goat.Goat.class, org.bukkit.entity.Goat.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.frog.Frog.class, org.bukkit.entity.Frog.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.frog.Tadpole.class, org.bukkit.entity.Tadpole.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.warden.Warden.class, org.bukkit.entity.Warden.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.allay.Allay.class, org.bukkit.entity.Allay.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.sniffer.Sniffer.class, org.bukkit.entity.Sniffer.class); ++ bukkitMap.put(Breeze.class, org.bukkit.entity.Breeze.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.armadillo.Armadillo.class, org.bukkit.entity.Armadillo.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Bogged.class, org.bukkit.entity.Bogged.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.creaking.Creaking.class, org.bukkit.entity.Creaking.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.AgeableWaterCreature.class, org.bukkit.entity.Squid.class); // close enough ++ } ++ ++ public static String getUsableName(Class clazz) { ++ String name = io.papermc.paper.util.MappingEnvironment.reobf() ? ObfHelper.INSTANCE.deobfClassName(clazz.getName()) : clazz.getName(); ++ name = name.substring(name.lastIndexOf(".") + 1); ++ boolean flag = false; ++ // inner classes ++ if (name.contains("$")) { ++ String cut = name.substring(name.indexOf("$") + 1); ++ if (cut.length() <= 2) { ++ name = name.replace("Entity", ""); ++ name = name.replace("$", "_"); ++ flag = true; ++ } else { ++ // mapped, wooo ++ name = cut; ++ } ++ } ++ name = name.replace("PathfinderGoal", ""); ++ name = name.replace("TargetGoal", ""); ++ name = name.replace("Goal", ""); ++ StringBuilder sb = new StringBuilder(); ++ for (char c : name.toCharArray()) { ++ if (c >= 'A' && c <= 'Z') { ++ sb.append("_"); ++ sb.append(Character.toLowerCase(c)); ++ } else { ++ sb.append(c); ++ } ++ } ++ name = sb.toString(); ++ name = name.replaceFirst("_", ""); ++ ++ if (flag && !deobfuscationMap.containsKey(name.toLowerCase(java.util.Locale.ROOT)) && !ignored.contains(name)) { ++ System.out.println("need to map " + clazz.getName() + " (" + name.toLowerCase(java.util.Locale.ROOT) + ")"); ++ } ++ ++ // did we rename this key? ++ return deobfuscationMap.getOrDefault(name, name); ++ } ++ ++ public static EnumSet vanillaToPaper(Goal goal) { ++ EnumSet goals = EnumSet.noneOf(GoalType.class); ++ for (GoalType type : GoalType.values()) { ++ if (goal.hasFlag(paperToVanilla(type))) { ++ goals.add(type); ++ } ++ } ++ return goals; ++ } ++ ++ public static GoalType vanillaToPaper(Goal.Flag type) { ++ switch (type) { ++ case MOVE: ++ return GoalType.MOVE; ++ case LOOK: ++ return GoalType.LOOK; ++ case JUMP: ++ return GoalType.JUMP; ++ case UNKNOWN_BEHAVIOR: ++ return GoalType.UNKNOWN_BEHAVIOR; ++ case TARGET: ++ return GoalType.TARGET; ++ default: ++ throw new IllegalArgumentException("Unknown vanilla mob goal type " + type.name()); ++ } ++ } ++ ++ public static EnumSet paperToVanilla(EnumSet types) { ++ EnumSet goals = EnumSet.noneOf(Goal.Flag.class); ++ for (GoalType type : types) { ++ goals.add(paperToVanilla(type)); ++ } ++ return goals; ++ } ++ ++ public static Goal.Flag paperToVanilla(GoalType type) { ++ switch (type) { ++ case MOVE: ++ return Goal.Flag.MOVE; ++ case LOOK: ++ return Goal.Flag.LOOK; ++ case JUMP: ++ return Goal.Flag.JUMP; ++ case UNKNOWN_BEHAVIOR: ++ return Goal.Flag.UNKNOWN_BEHAVIOR; ++ case TARGET: ++ return Goal.Flag.TARGET; ++ default: ++ throw new IllegalArgumentException("Unknown paper mob goal type " + type.name()); ++ } ++ } ++ ++ public static GoalKey getKey(Class goalClass) { ++ String name = getUsableName(goalClass); ++ if (ignored.contains(name)) { ++ //noinspection unchecked ++ return (GoalKey) GoalKey.of(Mob.class, NamespacedKey.minecraft(name)); ++ } ++ return GoalKey.of(getEntity(goalClass), NamespacedKey.minecraft(name)); ++ } ++ ++ public static Class getEntity(Class goalClass) { ++ //noinspection unchecked ++ return (Class) entityClassCache.computeIfAbsent(goalClass, key -> { ++ for (Constructor ctor : key.getDeclaredConstructors()) { ++ for (int i = 0; i < ctor.getParameterCount(); i++) { ++ Class param = ctor.getParameterTypes()[i]; ++ if (net.minecraft.world.entity.Mob.class.isAssignableFrom(param)) { ++ //noinspection unchecked ++ return toBukkitClass((Class) param); ++ } else if (RangedAttackMob.class.isAssignableFrom(param)) { ++ return RangedEntity.class; ++ } ++ } ++ } ++ throw new RuntimeException("Can't figure out applicable entity for mob goal " + goalClass); // maybe just return EntityInsentient? ++ }); ++ } ++ ++ public static Class toBukkitClass(Class nmsClass) { ++ Class bukkitClass = bukkitMap.get(nmsClass); ++ if (bukkitClass == null) { ++ throw new RuntimeException("Can't figure out applicable bukkit entity for nms entity " + nmsClass); // maybe just return Mob? ++ } ++ return bukkitClass; ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2625ff0d8fa1fb2b5166326dc729bc41b054779b +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java +@@ -0,0 +1,53 @@ ++package com.destroystokyo.paper.entity.ai; ++ ++import org.bukkit.entity.Mob; ++ ++/** ++ * Wraps api in vanilla ++ */ ++public class PaperCustomGoal extends net.minecraft.world.entity.ai.goal.Goal { ++ ++ private final Goal handle; ++ ++ public PaperCustomGoal(Goal handle) { ++ this.handle = handle; ++ ++ this.setFlags(MobGoalHelper.paperToVanilla(handle.getTypes())); ++ if (this.getFlags().size() == 0) { ++ this.addFlag(Flag.UNKNOWN_BEHAVIOR); ++ } ++ } ++ ++ @Override ++ public boolean canUse() { ++ return handle.shouldActivate(); ++ } ++ ++ @Override ++ public boolean canContinueToUse() { ++ return handle.shouldStayActive(); ++ } ++ ++ @Override ++ public void start() { ++ handle.start(); ++ } ++ ++ @Override ++ public void stop() { ++ handle.stop(); ++ } ++ ++ @Override ++ public void tick() { ++ handle.tick(); ++ } ++ ++ public Goal getHandle() { ++ return handle; ++ } ++ ++ public GoalKey getKey() { ++ return handle.getKey(); ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7e72fbb1659327452a2a1c665fd852b53670c85d +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java +@@ -0,0 +1,226 @@ ++package com.destroystokyo.paper.entity.ai; ++ ++import java.util.Collection; ++import java.util.EnumSet; ++import java.util.HashSet; ++import java.util.LinkedList; ++import java.util.List; ++import java.util.Set; ++import net.minecraft.world.entity.ai.goal.GoalSelector; ++import net.minecraft.world.entity.ai.goal.WrappedGoal; ++import org.bukkit.craftbukkit.entity.CraftMob; ++import org.bukkit.entity.Mob; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public class PaperMobGoals implements MobGoals { ++ ++ @Override ++ public void addGoal(T mob, int priority, Goal goal) { ++ CraftMob craftMob = (CraftMob) mob; ++ net.minecraft.world.entity.ai.goal.Goal mojangGoal; ++ ++ if (goal instanceof PaperVanillaGoal vanillaGoal) { ++ mojangGoal = vanillaGoal.getHandle(); ++ } else { ++ mojangGoal = new PaperCustomGoal<>(goal); ++ } ++ ++ getHandle(craftMob, goal.getTypes()).addGoal(priority, mojangGoal); ++ } ++ ++ @Override ++ public void removeGoal(T mob, Goal goal) { ++ CraftMob craftMob = (CraftMob) mob; ++ if (goal instanceof PaperCustomGoal) { ++ getHandle(craftMob, goal.getTypes()).removeGoal((net.minecraft.world.entity.ai.goal.Goal) goal); ++ } else if (goal instanceof PaperVanillaGoal) { ++ getHandle(craftMob, goal.getTypes()).removeGoal(((PaperVanillaGoal) goal).getHandle()); ++ } else { ++ List toRemove = new LinkedList<>(); ++ for (WrappedGoal item : getHandle(craftMob, goal.getTypes()).getAvailableGoals()) { ++ if (item.getGoal() instanceof PaperCustomGoal) { ++ //noinspection unchecked ++ if (((PaperCustomGoal) item.getGoal()).getHandle() == goal) { ++ toRemove.add(item.getGoal()); ++ } ++ } ++ } ++ ++ for (net.minecraft.world.entity.ai.goal.Goal g : toRemove) { ++ getHandle(craftMob, goal.getTypes()).removeGoal(g); ++ } ++ } ++ } ++ ++ @Override ++ public void removeAllGoals(T mob) { ++ for (GoalType type : GoalType.values()) { ++ removeAllGoals(mob, type); ++ } ++ } ++ ++ @Override ++ public void removeAllGoals(T mob, GoalType type) { ++ for (Goal goal : getAllGoals(mob, type)) { ++ removeGoal(mob, goal); ++ } ++ } ++ ++ @Override ++ public void removeGoal(T mob, GoalKey key) { ++ for (Goal goal : getGoals(mob, key)) { ++ removeGoal(mob, goal); ++ } ++ } ++ ++ @Override ++ public boolean hasGoal(T mob, GoalKey key) { ++ for (Goal g : getAllGoals(mob)) { ++ if (g.getKey().equals(key)) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ @Override ++ public Goal getGoal(T mob, GoalKey key) { ++ for (Goal g : getAllGoals(mob)) { ++ if (g.getKey().equals(key)) { ++ return g; ++ } ++ } ++ return null; ++ } ++ ++ @Override ++ public Collection> getGoals(T mob, GoalKey key) { ++ Set> goals = new HashSet<>(); ++ for (Goal g : getAllGoals(mob)) { ++ if (g.getKey().equals(key)) { ++ goals.add(g); ++ } ++ } ++ return goals; ++ } ++ ++ @Override ++ public Collection> getAllGoals(T mob) { ++ Set> goals = new HashSet<>(); ++ for (GoalType type : GoalType.values()) { ++ goals.addAll(getAllGoals(mob, type)); ++ } ++ return goals; ++ } ++ ++ @Override ++ public Collection> getAllGoals(T mob, GoalType type) { ++ CraftMob craftMob = (CraftMob) mob; ++ Set> goals = new HashSet<>(); ++ for (WrappedGoal item : getHandle(craftMob, type).getAvailableGoals()) { ++ if (!item.getGoal().hasFlag(MobGoalHelper.paperToVanilla(type))) { ++ continue; ++ } ++ ++ if (item.getGoal() instanceof PaperCustomGoal) { ++ //noinspection unchecked ++ goals.add(((PaperCustomGoal) item.getGoal()).getHandle()); ++ } else { ++ goals.add(item.getGoal().asPaperVanillaGoal()); ++ } ++ } ++ return goals; ++ } ++ ++ @Override ++ public Collection> getAllGoalsWithout(T mob, GoalType type) { ++ CraftMob craftMob = (CraftMob) mob; ++ Set> goals = new HashSet<>(); ++ for (GoalType internalType : GoalType.values()) { ++ if (internalType == type) { ++ continue; ++ } ++ for (WrappedGoal item : getHandle(craftMob, internalType).getAvailableGoals()) { ++ if (item.getGoal().hasFlag(MobGoalHelper.paperToVanilla(type))) { ++ continue; ++ } ++ ++ if (item.getGoal() instanceof PaperCustomGoal) { ++ //noinspection unchecked ++ goals.add(((PaperCustomGoal) item.getGoal()).getHandle()); ++ } else { ++ goals.add(item.getGoal().asPaperVanillaGoal()); ++ } ++ } ++ } ++ return goals; ++ } ++ ++ @Override ++ public Collection> getRunningGoals(T mob) { ++ Set> goals = new HashSet<>(); ++ for (GoalType type : GoalType.values()) { ++ goals.addAll(getRunningGoals(mob, type)); ++ } ++ return goals; ++ } ++ ++ @Override ++ public Collection> getRunningGoals(T mob, GoalType type) { ++ CraftMob craftMob = (CraftMob) mob; ++ Set> goals = new HashSet<>(); ++ getHandle(craftMob, type).getAvailableGoals() ++ .stream().filter(WrappedGoal::isRunning) ++ .filter(item -> item.getGoal().hasFlag(MobGoalHelper.paperToVanilla(type))) ++ .forEach(item -> { ++ if (item.getGoal() instanceof PaperCustomGoal) { ++ //noinspection unchecked ++ goals.add(((PaperCustomGoal) item.getGoal()).getHandle()); ++ } else { ++ goals.add(item.getGoal().asPaperVanillaGoal()); ++ } ++ }); ++ return goals; ++ } ++ ++ @Override ++ public Collection> getRunningGoalsWithout(T mob, GoalType type) { ++ CraftMob craftMob = (CraftMob) mob; ++ Set> goals = new HashSet<>(); ++ for (GoalType internalType : GoalType.values()) { ++ if (internalType == type) { ++ continue; ++ } ++ getHandle(craftMob, internalType).getAvailableGoals() ++ .stream() ++ .filter(WrappedGoal::isRunning) ++ .filter(item -> !item.getGoal().hasFlag(MobGoalHelper.paperToVanilla(type))) ++ .forEach(item -> { ++ if (item.getGoal() instanceof PaperCustomGoal) { ++ //noinspection unchecked ++ goals.add(((PaperCustomGoal) item.getGoal()).getHandle()); ++ } else { ++ goals.add(item.getGoal().asPaperVanillaGoal()); ++ } ++ }); ++ } ++ return goals; ++ } ++ ++ private GoalSelector getHandle(CraftMob mob, EnumSet types) { ++ if (types.contains(GoalType.TARGET)) { ++ return mob.getHandle().targetSelector; ++ } else { ++ return mob.getHandle().goalSelector; ++ } ++ } ++ ++ private GoalSelector getHandle(CraftMob mob, GoalType type) { ++ if (type == GoalType.TARGET) { ++ return mob.getHandle().targetSelector; ++ } else { ++ return mob.getHandle().goalSelector; ++ } ++ } ++} +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b5c594a5499556ad452d9939c75e150af8252e90 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java +@@ -0,0 +1,61 @@ ++package com.destroystokyo.paper.entity.ai; ++ ++import java.util.EnumSet; ++import net.minecraft.world.entity.ai.goal.Goal; ++import org.bukkit.entity.Mob; ++ ++/** ++ * Wraps vanilla in api ++ */ ++public class PaperVanillaGoal implements VanillaGoal { ++ ++ private final Goal handle; ++ private final GoalKey key; ++ ++ private final EnumSet types; ++ ++ public PaperVanillaGoal(Goal handle) { ++ this.handle = handle; ++ this.key = MobGoalHelper.getKey(handle.getClass()); ++ this.types = MobGoalHelper.vanillaToPaper(handle); ++ } ++ ++ public Goal getHandle() { ++ return handle; ++ } ++ ++ @Override ++ public boolean shouldActivate() { ++ return handle.canUse(); ++ } ++ ++ @Override ++ public boolean shouldStayActive() { ++ return handle.canContinueToUse(); ++ } ++ ++ @Override ++ public void start() { ++ handle.start(); ++ } ++ ++ @Override ++ public void stop() { ++ handle.stop(); ++ } ++ ++ @Override ++ public void tick() { ++ handle.tick(); ++ } ++ ++ @Override ++ public GoalKey getKey() { ++ return key; ++ } ++ ++ @Override ++ public EnumSet getTypes() { ++ return types; ++ } ++} +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java +index a8d6d7054110b5d95830296699f004418dae10db..7a98d6e0d7e9b8d3967bf9498fd25a0c3148e039 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java +@@ -46,6 +46,16 @@ public abstract class Goal { + return this.flags; + } + ++ // Paper start - Mob Goal API ++ public boolean hasFlag(final Goal.Flag flag) { ++ return this.flags.contains(flag); ++ } ++ ++ public void addFlag(final Goal.Flag flag) { ++ this.flags.add(flag); ++ } ++ // Paper end - Mob Goal API ++ + protected int adjustedTickDelay(int ticks) { + return this.requiresUpdateEveryTick() ? ticks : reducedTickDelay(ticks); + } +@@ -62,7 +72,19 @@ public abstract class Goal { + return (ServerLevel)world; + } + ++ // Paper start - Mob goal api ++ private com.destroystokyo.paper.entity.ai.PaperVanillaGoal vanillaGoal; ++ public com.destroystokyo.paper.entity.ai.Goal asPaperVanillaGoal() { ++ if(this.vanillaGoal == null) { ++ this.vanillaGoal = new com.destroystokyo.paper.entity.ai.PaperVanillaGoal<>(this); ++ } ++ //noinspection unchecked ++ return (com.destroystokyo.paper.entity.ai.Goal) this.vanillaGoal; ++ } ++ // Paper end - Mob goal api ++ + public static enum Flag { ++ UNKNOWN_BEHAVIOR, // Paper - add UNKNOWN_BEHAVIOR + MOVE, + LOOK, + JUMP, +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index e5a534c3cae53811899d33664b0a985c2442582c..4108eebafddc9c271be8c6eb5afbdca70e5fbb89 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2966,5 +2966,11 @@ public final class CraftServer implements Server { + public boolean isStopping() { + return net.minecraft.server.MinecraftServer.getServer().hasStopped(); + } ++ ++ private com.destroystokyo.paper.entity.ai.MobGoals mobGoals = new com.destroystokyo.paper.entity.ai.PaperMobGoals(); ++ @Override ++ public com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { ++ return mobGoals; ++ } + // Paper end + } diff --git a/patches/server/0347-Prevent-teleporting-dead-entities.patch b/patches/server/0347-Prevent-teleporting-dead-entities.patch deleted file mode 100644 index 75dbbc6f16..0000000000 --- a/patches/server/0347-Prevent-teleporting-dead-entities.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Tue, 3 Mar 2020 05:26:40 +0000 -Subject: [PATCH] Prevent teleporting dead entities - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 859aa632d063cdd033b99c63b6f3e8837356ed45..517c215d47737c551125dec785de2896560f4cb0 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1625,6 +1625,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - - public void internalTeleport(PositionMoveRotation positionmoverotation, Set set) { -+ // Paper start - Prevent teleporting dead entities -+ if (player.isRemoved()) { -+ LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName()); -+ if (server.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Attempt to teleport removed player"); -+ return; -+ } -+ // Paper end - Prevent teleporting dead entities - if (Float.isNaN(positionmoverotation.yRot())) { - positionmoverotation = new PositionMoveRotation(positionmoverotation.position(), positionmoverotation.deltaMovement(), 0, positionmoverotation.xRot()); - } diff --git a/patches/server/0348-Add-villager-reputation-API.patch b/patches/server/0348-Add-villager-reputation-API.patch new file mode 100644 index 0000000000..f08d60eeae --- /dev/null +++ b/patches/server/0348-Add-villager-reputation-API.patch @@ -0,0 +1,122 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Wed, 22 Apr 2020 23:29:20 +0200 +Subject: [PATCH] Add villager reputation API + +== AT == +public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips +public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips ()V +public net.minecraft.world.entity.ai.gossip.GossipContainer gossips + +diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java +index f06a5f0d9c5c877ddf963254d3124f5fe2d67282..aa32804bc9affe9a615d3ffaa513f6f09aab3f32 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java ++++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java +@@ -216,6 +216,43 @@ public class GossipContainer { + public void remove(GossipType gossipType) { + this.entries.removeInt(gossipType); + } ++ ++ // Paper start - Add villager reputation API ++ private static final GossipType[] TYPES = GossipType.values(); ++ public com.destroystokyo.paper.entity.villager.Reputation getPaperReputation() { ++ Map map = new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class); ++ for (Object2IntMap.Entry type : this.entries.object2IntEntrySet()) { ++ map.put(toApi(type.getKey()), type.getIntValue()); ++ } ++ ++ return new com.destroystokyo.paper.entity.villager.Reputation(map); ++ } ++ ++ public void assignFromPaperReputation(com.destroystokyo.paper.entity.villager.Reputation rep) { ++ for (GossipType type : TYPES) { ++ com.destroystokyo.paper.entity.villager.ReputationType api = toApi(type); ++ ++ if (rep.hasReputationSet(api)) { ++ int reputation = rep.getReputation(api); ++ if (reputation == 0) { ++ this.entries.removeInt(type); ++ } else { ++ this.entries.put(type, reputation); ++ } ++ } ++ } ++ } ++ ++ private static com.destroystokyo.paper.entity.villager.ReputationType toApi(GossipType type) { ++ return switch (type) { ++ case MAJOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_NEGATIVE; ++ case MINOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_NEGATIVE; ++ case MINOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_POSITIVE; ++ case MAJOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_POSITIVE; ++ case TRADING -> com.destroystokyo.paper.entity.villager.ReputationType.TRADING; ++ }; ++ } ++ // Paper end - Add villager reputation API + } + + static record GossipEntry(UUID target, GossipType type, int value) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +index ded319d10a5907b96abfd5620036b66a9aa3b3f7..45c44c46edee9f46b8e197f1f54ea2779bf1184c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +@@ -21,6 +21,13 @@ import org.bukkit.entity.ZombieVillager; + import org.bukkit.event.entity.CreatureSpawnEvent; + import org.bukkit.event.entity.EntityTransformEvent; + ++// Paper start ++import com.destroystokyo.paper.entity.villager.Reputation; ++import com.google.common.collect.Maps; ++import java.util.Map; ++import java.util.UUID; ++// Paper end ++ + public class CraftVillager extends CraftAbstractVillager implements Villager { + + public CraftVillager(CraftServer server, net.minecraft.world.entity.npc.Villager entity) { +@@ -299,4 +306,45 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { + return this.getKey().hashCode(); + } + } ++ ++ // Paper start - Add villager reputation API ++ @Override ++ public Reputation getReputation(UUID uniqueId) { ++ net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips rep = getHandle().getGossips().gossips.get(uniqueId); ++ if (rep == null) { ++ return new Reputation(new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class)); ++ } ++ ++ return rep.getPaperReputation(); ++ } ++ ++ @Override ++ public Map getReputations() { ++ return getHandle().getGossips().gossips.entrySet() ++ .stream() ++ .collect(java.util.stream.Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getPaperReputation())); ++ } ++ ++ @Override ++ public void setReputation(UUID uniqueId, Reputation reputation) { ++ net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips nmsReputation = ++ getHandle().getGossips().gossips.computeIfAbsent( ++ uniqueId, ++ key -> new net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips() ++ ); ++ nmsReputation.assignFromPaperReputation(reputation); ++ } ++ ++ @Override ++ public void setReputations(Map reputations) { ++ for (Map.Entry entry : reputations.entrySet()) { ++ setReputation(entry.getKey(), entry.getValue()); ++ } ++ } ++ ++ @Override ++ public void clearReputations() { ++ getHandle().getGossips().gossips.clear(); ++ } ++ // Paper end + } diff --git a/patches/server/0348-Implement-Mob-Goal-API.patch b/patches/server/0348-Implement-Mob-Goal-API.patch deleted file mode 100644 index 147803336e..0000000000 --- a/patches/server/0348-Implement-Mob-Goal-API.patch +++ /dev/null @@ -1,801 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MiniDigger -Date: Fri, 3 Jan 2020 16:26:19 +0100 -Subject: [PATCH] Implement Mob Goal API - - -diff --git a/build.gradle.kts b/build.gradle.kts -index d5ad109d2deb4fe756924ebaac4091017beb6b99..cc0a3c29aeb67e486fb75c1d6cc280192421c7cd 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -55,6 +55,7 @@ dependencies { - runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") - runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") - -+ testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test - testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") - testImplementation("org.junit.platform:junit-platform-suite-engine:1.10.0") - testImplementation("org.hamcrest:hamcrest:2.2") -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -new file mode 100644 -index 0000000000000000000000000000000000000000..36621b42f0dbca9d82a2ca284f30fd9eceab166e ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -@@ -0,0 +1,379 @@ -+package com.destroystokyo.paper.entity.ai; -+ -+import com.destroystokyo.paper.entity.RangedEntity; -+import com.google.common.collect.BiMap; -+import com.google.common.collect.HashBiMap; -+import io.papermc.paper.util.ObfHelper; -+import java.lang.reflect.Constructor; -+import java.util.EnumSet; -+import java.util.HashMap; -+import java.util.HashSet; -+import java.util.Map; -+import java.util.Set; -+import net.minecraft.world.entity.FlyingMob; -+import net.minecraft.world.entity.PathfinderMob; -+import net.minecraft.world.entity.TamableAnimal; -+import net.minecraft.world.entity.ai.goal.Goal; -+import net.minecraft.world.entity.ambient.AmbientCreature; -+import net.minecraft.world.entity.animal.AbstractFish; -+import net.minecraft.world.entity.animal.AbstractGolem; -+import net.minecraft.world.entity.animal.AbstractSchoolingFish; -+import net.minecraft.world.entity.animal.Animal; -+import net.minecraft.world.entity.animal.Pufferfish; -+import net.minecraft.world.entity.animal.ShoulderRidingEntity; -+import net.minecraft.world.entity.animal.SnowGolem; -+import net.minecraft.world.entity.animal.WaterAnimal; -+import net.minecraft.world.entity.animal.camel.Camel; -+import net.minecraft.world.entity.animal.horse.AbstractChestedHorse; -+import net.minecraft.world.entity.boss.wither.WitherBoss; -+import net.minecraft.world.entity.monster.AbstractIllager; -+import net.minecraft.world.entity.monster.EnderMan; -+import net.minecraft.world.entity.monster.PatrollingMonster; -+import net.minecraft.world.entity.monster.RangedAttackMob; -+import net.minecraft.world.entity.monster.SpellcasterIllager; -+import net.minecraft.world.entity.monster.ZombifiedPiglin; -+import net.minecraft.world.entity.monster.breeze.Breeze; -+import net.minecraft.world.entity.monster.piglin.AbstractPiglin; -+import org.bukkit.NamespacedKey; -+import org.bukkit.entity.AbstractHorse; -+import org.bukkit.entity.AbstractSkeleton; -+import org.bukkit.entity.AbstractVillager; -+import org.bukkit.entity.Ageable; -+import org.bukkit.entity.Ambient; -+import org.bukkit.entity.Animals; -+import org.bukkit.entity.Bat; -+import org.bukkit.entity.Bee; -+import org.bukkit.entity.Blaze; -+import org.bukkit.entity.Cat; -+import org.bukkit.entity.CaveSpider; -+import org.bukkit.entity.ChestedHorse; -+import org.bukkit.entity.Chicken; -+import org.bukkit.entity.Cod; -+import org.bukkit.entity.Cow; -+import org.bukkit.entity.Creature; -+import org.bukkit.entity.Creeper; -+import org.bukkit.entity.Dolphin; -+import org.bukkit.entity.Donkey; -+import org.bukkit.entity.Drowned; -+import org.bukkit.entity.ElderGuardian; -+import org.bukkit.entity.EnderDragon; -+import org.bukkit.entity.Enderman; -+import org.bukkit.entity.Endermite; -+import org.bukkit.entity.Evoker; -+import org.bukkit.entity.Fish; -+import org.bukkit.entity.Flying; -+import org.bukkit.entity.Fox; -+import org.bukkit.entity.Ghast; -+import org.bukkit.entity.Giant; -+import org.bukkit.entity.Golem; -+import org.bukkit.entity.Guardian; -+import org.bukkit.entity.Hoglin; -+import org.bukkit.entity.Horse; -+import org.bukkit.entity.Husk; -+import org.bukkit.entity.Illager; -+import org.bukkit.entity.Illusioner; -+import org.bukkit.entity.IronGolem; -+import org.bukkit.entity.Llama; -+import org.bukkit.entity.MagmaCube; -+import org.bukkit.entity.Mob; -+import org.bukkit.entity.Monster; -+import org.bukkit.entity.Mule; -+import org.bukkit.entity.MushroomCow; -+import org.bukkit.entity.Ocelot; -+import org.bukkit.entity.Panda; -+import org.bukkit.entity.Parrot; -+import org.bukkit.entity.Phantom; -+import org.bukkit.entity.Pig; -+import org.bukkit.entity.PigZombie; -+import org.bukkit.entity.Piglin; -+import org.bukkit.entity.PiglinAbstract; -+import org.bukkit.entity.PiglinBrute; -+import org.bukkit.entity.Pillager; -+import org.bukkit.entity.PolarBear; -+import org.bukkit.entity.PufferFish; -+import org.bukkit.entity.Rabbit; -+import org.bukkit.entity.Raider; -+import org.bukkit.entity.Ravager; -+import org.bukkit.entity.Salmon; -+import org.bukkit.entity.Sheep; -+import org.bukkit.entity.Shulker; -+import org.bukkit.entity.Silverfish; -+import org.bukkit.entity.Skeleton; -+import org.bukkit.entity.SkeletonHorse; -+import org.bukkit.entity.Slime; -+import org.bukkit.entity.Snowman; -+import org.bukkit.entity.Spellcaster; -+import org.bukkit.entity.Spider; -+import org.bukkit.entity.Squid; -+import org.bukkit.entity.Stray; -+import org.bukkit.entity.Strider; -+import org.bukkit.entity.Tameable; -+import org.bukkit.entity.TraderLlama; -+import org.bukkit.entity.TropicalFish; -+import org.bukkit.entity.Turtle; -+import org.bukkit.entity.Vex; -+import org.bukkit.entity.Villager; -+import org.bukkit.entity.Vindicator; -+import org.bukkit.entity.WanderingTrader; -+import org.bukkit.entity.WaterMob; -+import org.bukkit.entity.Witch; -+import org.bukkit.entity.Wither; -+import org.bukkit.entity.WitherSkeleton; -+import org.bukkit.entity.Wolf; -+import org.bukkit.entity.Zoglin; -+import org.bukkit.entity.Zombie; -+import org.bukkit.entity.ZombieHorse; -+import org.bukkit.entity.ZombieVillager; -+ -+public class MobGoalHelper { -+ -+ private static final BiMap deobfuscationMap = HashBiMap.create(); -+ private static final Map, Class> entityClassCache = new HashMap<>(); -+ private static final Map, Class> bukkitMap = new HashMap<>(); -+ -+ static final Set ignored = new HashSet<>(); -+ -+ static { -+ // TODO these kinda should be checked on each release, in case obfuscation changes -+ deobfuscationMap.put("abstract_skeleton_1", "abstract_skeleton_melee"); -+ -+ ignored.add("goal_selector_1"); -+ ignored.add("goal_selector_2"); -+ ignored.add("selector_1"); -+ ignored.add("selector_2"); -+ ignored.add("wrapped"); -+ -+ bukkitMap.put(net.minecraft.world.entity.Mob.class, Mob.class); -+ bukkitMap.put(net.minecraft.world.entity.AgeableMob.class, Ageable.class); -+ bukkitMap.put(AmbientCreature.class, Ambient.class); -+ bukkitMap.put(Animal.class, Animals.class); -+ bukkitMap.put(net.minecraft.world.entity.ambient.Bat.class, Bat.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Bee.class, Bee.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Blaze.class, Blaze.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Cat.class, Cat.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.CaveSpider.class, CaveSpider.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Chicken.class, Chicken.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Cod.class, Cod.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Cow.class, Cow.class); -+ bukkitMap.put(PathfinderMob.class, Creature.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Creeper.class, Creeper.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Dolphin.class, Dolphin.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Drowned.class, Drowned.class); -+ bukkitMap.put(net.minecraft.world.entity.boss.enderdragon.EnderDragon.class, EnderDragon.class); -+ bukkitMap.put(EnderMan.class, Enderman.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Endermite.class, Endermite.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Evoker.class, Evoker.class); -+ bukkitMap.put(AbstractFish.class, Fish.class); -+ bukkitMap.put(AbstractSchoolingFish.class, Fish.class); // close enough -+ bukkitMap.put(FlyingMob.class, Flying.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Fox.class, Fox.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Ghast.class, Ghast.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Giant.class, Giant.class); -+ bukkitMap.put(AbstractGolem.class, Golem.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Guardian.class, Guardian.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.ElderGuardian.class, ElderGuardian.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Horse.class, Horse.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.horse.AbstractHorse.class, AbstractHorse.class); -+ bukkitMap.put(AbstractChestedHorse.class, ChestedHorse.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Donkey.class, Donkey.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Mule.class, Mule.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.horse.SkeletonHorse.class, SkeletonHorse.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.horse.ZombieHorse.class, ZombieHorse.class); -+ bukkitMap.put(Camel.class, org.bukkit.entity.Camel.class); -+ bukkitMap.put(AbstractIllager.class, Illager.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Illusioner.class, Illusioner.class); -+ bukkitMap.put(SpellcasterIllager.class, Spellcaster.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.IronGolem.class, IronGolem.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Llama.class, Llama.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.horse.TraderLlama.class, TraderLlama.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.MagmaCube.class, MagmaCube.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Monster.class, Monster.class); -+ bukkitMap.put(PatrollingMonster.class, Raider.class); // close enough -+ bukkitMap.put(net.minecraft.world.entity.animal.MushroomCow.class, MushroomCow.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Ocelot.class, Ocelot.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Panda.class, Panda.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Parrot.class, Parrot.class); -+ bukkitMap.put(ShoulderRidingEntity.class, Parrot.class); // close enough -+ bukkitMap.put(net.minecraft.world.entity.monster.Phantom.class, Phantom.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Pig.class, Pig.class); -+ bukkitMap.put(ZombifiedPiglin.class, PigZombie.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Pillager.class, Pillager.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.PolarBear.class, PolarBear.class); -+ bukkitMap.put(Pufferfish.class, PufferFish.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Rabbit.class, Rabbit.class); -+ bukkitMap.put(net.minecraft.world.entity.raid.Raider.class, Raider.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Ravager.class, Ravager.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Salmon.class, Salmon.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Sheep.class, Sheep.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Shulker.class, Shulker.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Silverfish.class, Silverfish.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Skeleton.class, Skeleton.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.AbstractSkeleton.class, AbstractSkeleton.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Stray.class, Stray.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.WitherSkeleton.class, WitherSkeleton.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Slime.class, Slime.class); -+ bukkitMap.put(SnowGolem.class, Snowman.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Spider.class, Spider.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Squid.class, Squid.class); -+ bukkitMap.put(TamableAnimal.class, Tameable.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.TropicalFish.class, TropicalFish.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Turtle.class, Turtle.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Vex.class, Vex.class); -+ bukkitMap.put(net.minecraft.world.entity.npc.Villager.class, Villager.class); -+ bukkitMap.put(net.minecraft.world.entity.npc.AbstractVillager.class, AbstractVillager.class); -+ bukkitMap.put(net.minecraft.world.entity.npc.WanderingTrader.class, WanderingTrader.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Vindicator.class, Vindicator.class); -+ bukkitMap.put(WaterAnimal.class, WaterMob.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Witch.class, Witch.class); -+ bukkitMap.put(WitherBoss.class, Wither.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.Wolf.class, Wolf.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Zombie.class, Zombie.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Husk.class, Husk.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.ZombieVillager.class, ZombieVillager.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.hoglin.Hoglin.class, Hoglin.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.piglin.Piglin.class, Piglin.class); -+ bukkitMap.put(AbstractPiglin.class, PiglinAbstract.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.piglin.PiglinBrute.class, PiglinBrute.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Strider.class, Strider.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Zoglin.class, Zoglin.class); -+ bukkitMap.put(net.minecraft.world.entity.GlowSquid.class, org.bukkit.entity.GlowSquid.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.axolotl.Axolotl.class, org.bukkit.entity.Axolotl.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.goat.Goat.class, org.bukkit.entity.Goat.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.frog.Frog.class, org.bukkit.entity.Frog.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.frog.Tadpole.class, org.bukkit.entity.Tadpole.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.warden.Warden.class, org.bukkit.entity.Warden.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.allay.Allay.class, org.bukkit.entity.Allay.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.sniffer.Sniffer.class, org.bukkit.entity.Sniffer.class); -+ bukkitMap.put(Breeze.class, org.bukkit.entity.Breeze.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.armadillo.Armadillo.class, org.bukkit.entity.Armadillo.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.Bogged.class, org.bukkit.entity.Bogged.class); -+ bukkitMap.put(net.minecraft.world.entity.monster.creaking.Creaking.class, org.bukkit.entity.Creaking.class); -+ bukkitMap.put(net.minecraft.world.entity.animal.AgeableWaterCreature.class, org.bukkit.entity.Squid.class); // close enough -+ } -+ -+ public static String getUsableName(Class clazz) { -+ String name = io.papermc.paper.util.MappingEnvironment.reobf() ? ObfHelper.INSTANCE.deobfClassName(clazz.getName()) : clazz.getName(); -+ name = name.substring(name.lastIndexOf(".") + 1); -+ boolean flag = false; -+ // inner classes -+ if (name.contains("$")) { -+ String cut = name.substring(name.indexOf("$") + 1); -+ if (cut.length() <= 2) { -+ name = name.replace("Entity", ""); -+ name = name.replace("$", "_"); -+ flag = true; -+ } else { -+ // mapped, wooo -+ name = cut; -+ } -+ } -+ name = name.replace("PathfinderGoal", ""); -+ name = name.replace("TargetGoal", ""); -+ name = name.replace("Goal", ""); -+ StringBuilder sb = new StringBuilder(); -+ for (char c : name.toCharArray()) { -+ if (c >= 'A' && c <= 'Z') { -+ sb.append("_"); -+ sb.append(Character.toLowerCase(c)); -+ } else { -+ sb.append(c); -+ } -+ } -+ name = sb.toString(); -+ name = name.replaceFirst("_", ""); -+ -+ if (flag && !deobfuscationMap.containsKey(name.toLowerCase(java.util.Locale.ROOT)) && !ignored.contains(name)) { -+ System.out.println("need to map " + clazz.getName() + " (" + name.toLowerCase(java.util.Locale.ROOT) + ")"); -+ } -+ -+ // did we rename this key? -+ return deobfuscationMap.getOrDefault(name, name); -+ } -+ -+ public static EnumSet vanillaToPaper(Goal goal) { -+ EnumSet goals = EnumSet.noneOf(GoalType.class); -+ for (GoalType type : GoalType.values()) { -+ if (goal.getFlags().hasElement(paperToVanilla(type))) { -+ goals.add(type); -+ } -+ } -+ return goals; -+ } -+ -+ public static GoalType vanillaToPaper(Goal.Flag type) { -+ switch (type) { -+ case MOVE: -+ return GoalType.MOVE; -+ case LOOK: -+ return GoalType.LOOK; -+ case JUMP: -+ return GoalType.JUMP; -+ case UNKNOWN_BEHAVIOR: -+ return GoalType.UNKNOWN_BEHAVIOR; -+ case TARGET: -+ return GoalType.TARGET; -+ default: -+ throw new IllegalArgumentException("Unknown vanilla mob goal type " + type.name()); -+ } -+ } -+ -+ public static EnumSet paperToVanilla(EnumSet types) { -+ EnumSet goals = EnumSet.noneOf(Goal.Flag.class); -+ for (GoalType type : types) { -+ goals.add(paperToVanilla(type)); -+ } -+ return goals; -+ } -+ -+ public static Goal.Flag paperToVanilla(GoalType type) { -+ switch (type) { -+ case MOVE: -+ return Goal.Flag.MOVE; -+ case LOOK: -+ return Goal.Flag.LOOK; -+ case JUMP: -+ return Goal.Flag.JUMP; -+ case UNKNOWN_BEHAVIOR: -+ return Goal.Flag.UNKNOWN_BEHAVIOR; -+ case TARGET: -+ return Goal.Flag.TARGET; -+ default: -+ throw new IllegalArgumentException("Unknown paper mob goal type " + type.name()); -+ } -+ } -+ -+ public static GoalKey getKey(Class goalClass) { -+ String name = getUsableName(goalClass); -+ if (ignored.contains(name)) { -+ //noinspection unchecked -+ return (GoalKey) GoalKey.of(Mob.class, NamespacedKey.minecraft(name)); -+ } -+ return GoalKey.of(getEntity(goalClass), NamespacedKey.minecraft(name)); -+ } -+ -+ public static Class getEntity(Class goalClass) { -+ //noinspection unchecked -+ return (Class) entityClassCache.computeIfAbsent(goalClass, key -> { -+ for (Constructor ctor : key.getDeclaredConstructors()) { -+ for (int i = 0; i < ctor.getParameterCount(); i++) { -+ Class param = ctor.getParameterTypes()[i]; -+ if (net.minecraft.world.entity.Mob.class.isAssignableFrom(param)) { -+ //noinspection unchecked -+ return toBukkitClass((Class) param); -+ } else if (RangedAttackMob.class.isAssignableFrom(param)) { -+ return RangedEntity.class; -+ } -+ } -+ } -+ throw new RuntimeException("Can't figure out applicable entity for mob goal " + goalClass); // maybe just return EntityInsentient? -+ }); -+ } -+ -+ public static Class toBukkitClass(Class nmsClass) { -+ Class bukkitClass = bukkitMap.get(nmsClass); -+ if (bukkitClass == null) { -+ throw new RuntimeException("Can't figure out applicable bukkit entity for nms entity " + nmsClass); // maybe just return Mob? -+ } -+ return bukkitClass; -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java -new file mode 100644 -index 0000000000000000000000000000000000000000..26c745dd9ccdfdd5c5039f2acc5201b9b91fb274 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java -@@ -0,0 +1,53 @@ -+package com.destroystokyo.paper.entity.ai; -+ -+import org.bukkit.entity.Mob; -+ -+/** -+ * Wraps api in vanilla -+ */ -+public class PaperCustomGoal extends net.minecraft.world.entity.ai.goal.Goal { -+ -+ private final Goal handle; -+ -+ public PaperCustomGoal(Goal handle) { -+ this.handle = handle; -+ -+ this.setFlags(MobGoalHelper.paperToVanilla(handle.getTypes())); -+ if (this.getFlags().size() == 0) { -+ this.getFlags().addUnchecked(Flag.UNKNOWN_BEHAVIOR); -+ } -+ } -+ -+ @Override -+ public boolean canUse() { -+ return handle.shouldActivate(); -+ } -+ -+ @Override -+ public boolean canContinueToUse() { -+ return handle.shouldStayActive(); -+ } -+ -+ @Override -+ public void start() { -+ handle.start(); -+ } -+ -+ @Override -+ public void stop() { -+ handle.stop(); -+ } -+ -+ @Override -+ public void tick() { -+ handle.tick(); -+ } -+ -+ public Goal getHandle() { -+ return handle; -+ } -+ -+ public GoalKey getKey() { -+ return handle.getKey(); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e8a427ea777af040d0e2b9cc0ba2a80b9176d026 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java -@@ -0,0 +1,226 @@ -+package com.destroystokyo.paper.entity.ai; -+ -+import java.util.Collection; -+import java.util.EnumSet; -+import java.util.HashSet; -+import java.util.LinkedList; -+import java.util.List; -+import java.util.Set; -+import net.minecraft.world.entity.ai.goal.GoalSelector; -+import net.minecraft.world.entity.ai.goal.WrappedGoal; -+import org.bukkit.craftbukkit.entity.CraftMob; -+import org.bukkit.entity.Mob; -+import org.jspecify.annotations.NullMarked; -+ -+@NullMarked -+public class PaperMobGoals implements MobGoals { -+ -+ @Override -+ public void addGoal(T mob, int priority, Goal goal) { -+ CraftMob craftMob = (CraftMob) mob; -+ net.minecraft.world.entity.ai.goal.Goal mojangGoal; -+ -+ if (goal instanceof PaperVanillaGoal vanillaGoal) { -+ mojangGoal = vanillaGoal.getHandle(); -+ } else { -+ mojangGoal = new PaperCustomGoal<>(goal); -+ } -+ -+ getHandle(craftMob, goal.getTypes()).addGoal(priority, mojangGoal); -+ } -+ -+ @Override -+ public void removeGoal(T mob, Goal goal) { -+ CraftMob craftMob = (CraftMob) mob; -+ if (goal instanceof PaperCustomGoal) { -+ getHandle(craftMob, goal.getTypes()).removeGoal((net.minecraft.world.entity.ai.goal.Goal) goal); -+ } else if (goal instanceof PaperVanillaGoal) { -+ getHandle(craftMob, goal.getTypes()).removeGoal(((PaperVanillaGoal) goal).getHandle()); -+ } else { -+ List toRemove = new LinkedList<>(); -+ for (WrappedGoal item : getHandle(craftMob, goal.getTypes()).getAvailableGoals()) { -+ if (item.getGoal() instanceof PaperCustomGoal) { -+ //noinspection unchecked -+ if (((PaperCustomGoal) item.getGoal()).getHandle() == goal) { -+ toRemove.add(item.getGoal()); -+ } -+ } -+ } -+ -+ for (net.minecraft.world.entity.ai.goal.Goal g : toRemove) { -+ getHandle(craftMob, goal.getTypes()).removeGoal(g); -+ } -+ } -+ } -+ -+ @Override -+ public void removeAllGoals(T mob) { -+ for (GoalType type : GoalType.values()) { -+ removeAllGoals(mob, type); -+ } -+ } -+ -+ @Override -+ public void removeAllGoals(T mob, GoalType type) { -+ for (Goal goal : getAllGoals(mob, type)) { -+ removeGoal(mob, goal); -+ } -+ } -+ -+ @Override -+ public void removeGoal(T mob, GoalKey key) { -+ for (Goal goal : getGoals(mob, key)) { -+ removeGoal(mob, goal); -+ } -+ } -+ -+ @Override -+ public boolean hasGoal(T mob, GoalKey key) { -+ for (Goal g : getAllGoals(mob)) { -+ if (g.getKey().equals(key)) { -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ @Override -+ public Goal getGoal(T mob, GoalKey key) { -+ for (Goal g : getAllGoals(mob)) { -+ if (g.getKey().equals(key)) { -+ return g; -+ } -+ } -+ return null; -+ } -+ -+ @Override -+ public Collection> getGoals(T mob, GoalKey key) { -+ Set> goals = new HashSet<>(); -+ for (Goal g : getAllGoals(mob)) { -+ if (g.getKey().equals(key)) { -+ goals.add(g); -+ } -+ } -+ return goals; -+ } -+ -+ @Override -+ public Collection> getAllGoals(T mob) { -+ Set> goals = new HashSet<>(); -+ for (GoalType type : GoalType.values()) { -+ goals.addAll(getAllGoals(mob, type)); -+ } -+ return goals; -+ } -+ -+ @Override -+ public Collection> getAllGoals(T mob, GoalType type) { -+ CraftMob craftMob = (CraftMob) mob; -+ Set> goals = new HashSet<>(); -+ for (WrappedGoal item : getHandle(craftMob, type).getAvailableGoals()) { -+ if (!item.getGoal().getFlags().hasElement(MobGoalHelper.paperToVanilla(type))) { -+ continue; -+ } -+ -+ if (item.getGoal() instanceof PaperCustomGoal) { -+ //noinspection unchecked -+ goals.add(((PaperCustomGoal) item.getGoal()).getHandle()); -+ } else { -+ goals.add(item.getGoal().asPaperVanillaGoal()); -+ } -+ } -+ return goals; -+ } -+ -+ @Override -+ public Collection> getAllGoalsWithout(T mob, GoalType type) { -+ CraftMob craftMob = (CraftMob) mob; -+ Set> goals = new HashSet<>(); -+ for (GoalType internalType : GoalType.values()) { -+ if (internalType == type) { -+ continue; -+ } -+ for (WrappedGoal item : getHandle(craftMob, internalType).getAvailableGoals()) { -+ if (item.getGoal().getFlags().hasElement(MobGoalHelper.paperToVanilla(type))) { -+ continue; -+ } -+ -+ if (item.getGoal() instanceof PaperCustomGoal) { -+ //noinspection unchecked -+ goals.add(((PaperCustomGoal) item.getGoal()).getHandle()); -+ } else { -+ goals.add(item.getGoal().asPaperVanillaGoal()); -+ } -+ } -+ } -+ return goals; -+ } -+ -+ @Override -+ public Collection> getRunningGoals(T mob) { -+ Set> goals = new HashSet<>(); -+ for (GoalType type : GoalType.values()) { -+ goals.addAll(getRunningGoals(mob, type)); -+ } -+ return goals; -+ } -+ -+ @Override -+ public Collection> getRunningGoals(T mob, GoalType type) { -+ CraftMob craftMob = (CraftMob) mob; -+ Set> goals = new HashSet<>(); -+ getHandle(craftMob, type).getAvailableGoals() -+ .stream().filter(WrappedGoal::isRunning) -+ .filter(item -> item.getGoal().getFlags().hasElement(MobGoalHelper.paperToVanilla(type))) -+ .forEach(item -> { -+ if (item.getGoal() instanceof PaperCustomGoal) { -+ //noinspection unchecked -+ goals.add(((PaperCustomGoal) item.getGoal()).getHandle()); -+ } else { -+ goals.add(item.getGoal().asPaperVanillaGoal()); -+ } -+ }); -+ return goals; -+ } -+ -+ @Override -+ public Collection> getRunningGoalsWithout(T mob, GoalType type) { -+ CraftMob craftMob = (CraftMob) mob; -+ Set> goals = new HashSet<>(); -+ for (GoalType internalType : GoalType.values()) { -+ if (internalType == type) { -+ continue; -+ } -+ getHandle(craftMob, internalType).getAvailableGoals() -+ .stream() -+ .filter(WrappedGoal::isRunning) -+ .filter(item -> !item.getGoal().getFlags().hasElement(MobGoalHelper.paperToVanilla(type))) -+ .forEach(item -> { -+ if (item.getGoal() instanceof PaperCustomGoal) { -+ //noinspection unchecked -+ goals.add(((PaperCustomGoal) item.getGoal()).getHandle()); -+ } else { -+ goals.add(item.getGoal().asPaperVanillaGoal()); -+ } -+ }); -+ } -+ return goals; -+ } -+ -+ private GoalSelector getHandle(CraftMob mob, EnumSet types) { -+ if (types.contains(GoalType.TARGET)) { -+ return mob.getHandle().targetSelector; -+ } else { -+ return mob.getHandle().goalSelector; -+ } -+ } -+ -+ private GoalSelector getHandle(CraftMob mob, GoalType type) { -+ if (type == GoalType.TARGET) { -+ return mob.getHandle().targetSelector; -+ } else { -+ return mob.getHandle().goalSelector; -+ } -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b5c594a5499556ad452d9939c75e150af8252e90 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java -@@ -0,0 +1,61 @@ -+package com.destroystokyo.paper.entity.ai; -+ -+import java.util.EnumSet; -+import net.minecraft.world.entity.ai.goal.Goal; -+import org.bukkit.entity.Mob; -+ -+/** -+ * Wraps vanilla in api -+ */ -+public class PaperVanillaGoal implements VanillaGoal { -+ -+ private final Goal handle; -+ private final GoalKey key; -+ -+ private final EnumSet types; -+ -+ public PaperVanillaGoal(Goal handle) { -+ this.handle = handle; -+ this.key = MobGoalHelper.getKey(handle.getClass()); -+ this.types = MobGoalHelper.vanillaToPaper(handle); -+ } -+ -+ public Goal getHandle() { -+ return handle; -+ } -+ -+ @Override -+ public boolean shouldActivate() { -+ return handle.canUse(); -+ } -+ -+ @Override -+ public boolean shouldStayActive() { -+ return handle.canContinueToUse(); -+ } -+ -+ @Override -+ public void start() { -+ handle.start(); -+ } -+ -+ @Override -+ public void stop() { -+ handle.stop(); -+ } -+ -+ @Override -+ public void tick() { -+ handle.tick(); -+ } -+ -+ @Override -+ public GoalKey getKey() { -+ return key; -+ } -+ -+ @Override -+ public EnumSet getTypes() { -+ return types; -+ } -+} -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java -index a8d6d7054110b5d95830296699f004418dae10db..acc25b08ed3b9f978229fa017d23f9fa0da519e3 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java -@@ -62,7 +62,19 @@ public abstract class Goal { - return (ServerLevel)world; - } - -+ // Paper start - Mob goal api -+ private com.destroystokyo.paper.entity.ai.PaperVanillaGoal vanillaGoal; -+ public com.destroystokyo.paper.entity.ai.Goal asPaperVanillaGoal() { -+ if(this.vanillaGoal == null) { -+ this.vanillaGoal = new com.destroystokyo.paper.entity.ai.PaperVanillaGoal<>(this); -+ } -+ //noinspection unchecked -+ return (com.destroystokyo.paper.entity.ai.Goal) this.vanillaGoal; -+ } -+ // Paper end - Mob goal api -+ - public static enum Flag { -+ UNKNOWN_BEHAVIOR, // Paper - add UNKNOWN_BEHAVIOR - MOVE, - LOOK, - JUMP, -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index e5a534c3cae53811899d33664b0a985c2442582c..4108eebafddc9c271be8c6eb5afbdca70e5fbb89 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2966,5 +2966,11 @@ public final class CraftServer implements Server { - public boolean isStopping() { - return net.minecraft.server.MinecraftServer.getServer().hasStopped(); - } -+ -+ private com.destroystokyo.paper.entity.ai.MobGoals mobGoals = new com.destroystokyo.paper.entity.ai.PaperMobGoals(); -+ @Override -+ public com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { -+ return mobGoals; -+ } - // Paper end - } diff --git a/patches/server/0349-Add-villager-reputation-API.patch b/patches/server/0349-Add-villager-reputation-API.patch deleted file mode 100644 index f08d60eeae..0000000000 --- a/patches/server/0349-Add-villager-reputation-API.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Wed, 22 Apr 2020 23:29:20 +0200 -Subject: [PATCH] Add villager reputation API - -== AT == -public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips -public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips ()V -public net.minecraft.world.entity.ai.gossip.GossipContainer gossips - -diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java -index f06a5f0d9c5c877ddf963254d3124f5fe2d67282..aa32804bc9affe9a615d3ffaa513f6f09aab3f32 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java -+++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java -@@ -216,6 +216,43 @@ public class GossipContainer { - public void remove(GossipType gossipType) { - this.entries.removeInt(gossipType); - } -+ -+ // Paper start - Add villager reputation API -+ private static final GossipType[] TYPES = GossipType.values(); -+ public com.destroystokyo.paper.entity.villager.Reputation getPaperReputation() { -+ Map map = new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class); -+ for (Object2IntMap.Entry type : this.entries.object2IntEntrySet()) { -+ map.put(toApi(type.getKey()), type.getIntValue()); -+ } -+ -+ return new com.destroystokyo.paper.entity.villager.Reputation(map); -+ } -+ -+ public void assignFromPaperReputation(com.destroystokyo.paper.entity.villager.Reputation rep) { -+ for (GossipType type : TYPES) { -+ com.destroystokyo.paper.entity.villager.ReputationType api = toApi(type); -+ -+ if (rep.hasReputationSet(api)) { -+ int reputation = rep.getReputation(api); -+ if (reputation == 0) { -+ this.entries.removeInt(type); -+ } else { -+ this.entries.put(type, reputation); -+ } -+ } -+ } -+ } -+ -+ private static com.destroystokyo.paper.entity.villager.ReputationType toApi(GossipType type) { -+ return switch (type) { -+ case MAJOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_NEGATIVE; -+ case MINOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_NEGATIVE; -+ case MINOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_POSITIVE; -+ case MAJOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_POSITIVE; -+ case TRADING -> com.destroystokyo.paper.entity.villager.ReputationType.TRADING; -+ }; -+ } -+ // Paper end - Add villager reputation API - } - - static record GossipEntry(UUID target, GossipType type, int value) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -index ded319d10a5907b96abfd5620036b66a9aa3b3f7..45c44c46edee9f46b8e197f1f54ea2779bf1184c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -@@ -21,6 +21,13 @@ import org.bukkit.entity.ZombieVillager; - import org.bukkit.event.entity.CreatureSpawnEvent; - import org.bukkit.event.entity.EntityTransformEvent; - -+// Paper start -+import com.destroystokyo.paper.entity.villager.Reputation; -+import com.google.common.collect.Maps; -+import java.util.Map; -+import java.util.UUID; -+// Paper end -+ - public class CraftVillager extends CraftAbstractVillager implements Villager { - - public CraftVillager(CraftServer server, net.minecraft.world.entity.npc.Villager entity) { -@@ -299,4 +306,45 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { - return this.getKey().hashCode(); - } - } -+ -+ // Paper start - Add villager reputation API -+ @Override -+ public Reputation getReputation(UUID uniqueId) { -+ net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips rep = getHandle().getGossips().gossips.get(uniqueId); -+ if (rep == null) { -+ return new Reputation(new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class)); -+ } -+ -+ return rep.getPaperReputation(); -+ } -+ -+ @Override -+ public Map getReputations() { -+ return getHandle().getGossips().gossips.entrySet() -+ .stream() -+ .collect(java.util.stream.Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getPaperReputation())); -+ } -+ -+ @Override -+ public void setReputation(UUID uniqueId, Reputation reputation) { -+ net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips nmsReputation = -+ getHandle().getGossips().gossips.computeIfAbsent( -+ uniqueId, -+ key -> new net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips() -+ ); -+ nmsReputation.assignFromPaperReputation(reputation); -+ } -+ -+ @Override -+ public void setReputations(Map reputations) { -+ for (Map.Entry entry : reputations.entrySet()) { -+ setReputation(entry.getKey(), entry.getValue()); -+ } -+ } -+ -+ @Override -+ public void clearReputations() { -+ getHandle().getGossips().gossips.clear(); -+ } -+ // Paper end - } diff --git a/patches/server/0349-ExperienceOrb-merging-stacking-API-and-fixes.patch b/patches/server/0349-ExperienceOrb-merging-stacking-API-and-fixes.patch new file mode 100644 index 0000000000..83f8e86f82 --- /dev/null +++ b/patches/server/0349-ExperienceOrb-merging-stacking-API-and-fixes.patch @@ -0,0 +1,113 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 10 Nov 2017 23:03:12 -0500 +Subject: [PATCH] ExperienceOrb merging/stacking API and fixes + +Adds an option for maximum exp value when merging orbs + +Adds ExperienceOrbMergeEvent +Fired when the server is about to merge 2 experience orbs +as entities. Plugins can cancel it if they want to ensure experience orbs do not lose important +metadata such as spawn reason, or conditionally move data from source to target. + +Fixes an issue where the stacked count was not taking into account +for mending repairs and when merging with spigot's merge-on-spawn +logic + +== AT == +public net.minecraft.world.entity.ExperienceOrb count + +Co-authored-by: Aikar +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java +index 9ef7227c2b88f9d0e92e70b33bbd97e22bd71eca..42e8dc24e5cb7b02639d4b80f831b8856f0f45d5 100644 +--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java ++++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java +@@ -247,6 +247,7 @@ public class ExperienceOrb extends Entity { + } + + private static boolean tryMergeToExisting(ServerLevel world, Vec3 pos, int amount) { ++ // Paper - TODO some other event for this kind of merge + AABB axisalignedbb = AABB.ofSize(pos, 1.0D, 1.0D, 1.0D); + int j = world.getRandom().nextInt(40); + List list = world.getEntities(EntityTypeTest.forClass(ExperienceOrb.class), axisalignedbb, (entityexperienceorb) -> { +@@ -273,6 +274,11 @@ public class ExperienceOrb extends Entity { + } + + private void merge(ExperienceOrb other) { ++ // Paper start - call orb merge event ++ if (!new com.destroystokyo.paper.event.entity.ExperienceOrbMergeEvent((org.bukkit.entity.ExperienceOrb) this.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) other.getBukkitEntity()).callEvent()) { ++ return; ++ } ++ // Paper end - call orb merge event + this.count += other.count; + this.age = Math.min(this.age, other.age); + other.discard(EntityRemoveEvent.Cause.MERGE); // CraftBukkit - add Bukkit remove cause +@@ -366,7 +372,7 @@ public class ExperienceOrb extends Entity { + int l = amount - k * amount / j; + + if (l > 0) { +- this.value = l; // CraftBukkit - update exp value of orb for PlayerItemMendEvent calls ++ // 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 + return this.repairPlayerItems(player, l); + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java +index 5a7d314ec0562e472f5dc45924a7b24841cff126..650e4a01cecc4cc08e7ff9ebcc4c367084351f21 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java +@@ -18,6 +18,18 @@ public class CraftExperienceOrb extends CraftEntity implements ExperienceOrb { + this.getHandle().value = value; + } + ++ // Paper start - expose count ++ @Override ++ public int getCount() { ++ return this.getHandle().count; ++ } ++ ++ @Override ++ public void setCount(final int count) { ++ this.getHandle().count = count; ++ } ++ // Paper end ++ + // Paper start + public java.util.UUID getTriggerEntityId() { + return getHandle().triggerEntityId; +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index f482fc14e171129f9fa60113b1223b2db79ec6ec..b8e1a7251f9fa09f03b00b387013af1c623a1e52 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -712,15 +712,29 @@ public class CraftEventFactory { + if (entity instanceof net.minecraft.world.entity.ExperienceOrb xp) { + double radius = world.spigotConfig.expMerge; + if (radius > 0) { ++ // 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; ++ if (mergeUnconditionally || xp.value < maxValue) { // Paper - Skip iteration if unnecessary ++ + List entities = world.getEntities(entity, entity.getBoundingBox().inflate(radius, radius, radius)); + for (Entity e : entities) { + if (e instanceof net.minecraft.world.entity.ExperienceOrb loopItem) { +- if (!loopItem.isRemoved()) { ++ // Paper start ++ if (!loopItem.isRemoved() && xp.count == loopItem.count && (mergeUnconditionally || loopItem.value < maxValue) && new com.destroystokyo.paper.event.entity.ExperienceOrbMergeEvent((org.bukkit.entity.ExperienceOrb) entity.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) loopItem.getBukkitEntity()).callEvent()) { // Paper - ExperienceOrbMergeEvent ++ long newTotal = (long)xp.value + (long)loopItem.value; ++ if ((int) newTotal < 0) continue; // Overflow ++ if (!mergeUnconditionally && newTotal > maxValue) { ++ loopItem.value = (int) (newTotal - maxValue); ++ xp.value = (int) maxValue; ++ } else { + xp.value += loopItem.value; + loopItem.discard(null); // Add Bukkit remove cause ++ } // Paper end - Maximum exp value when merging + } + } + } ++ } // Paper end - End iteration skip check - All tweaking ends here + } + } + // Spigot end diff --git a/patches/server/0350-ExperienceOrb-merging-stacking-API-and-fixes.patch b/patches/server/0350-ExperienceOrb-merging-stacking-API-and-fixes.patch deleted file mode 100644 index 83f8e86f82..0000000000 --- a/patches/server/0350-ExperienceOrb-merging-stacking-API-and-fixes.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 10 Nov 2017 23:03:12 -0500 -Subject: [PATCH] ExperienceOrb merging/stacking API and fixes - -Adds an option for maximum exp value when merging orbs - -Adds ExperienceOrbMergeEvent -Fired when the server is about to merge 2 experience orbs -as entities. Plugins can cancel it if they want to ensure experience orbs do not lose important -metadata such as spawn reason, or conditionally move data from source to target. - -Fixes an issue where the stacked count was not taking into account -for mending repairs and when merging with spigot's merge-on-spawn -logic - -== AT == -public net.minecraft.world.entity.ExperienceOrb count - -Co-authored-by: Aikar -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -index 9ef7227c2b88f9d0e92e70b33bbd97e22bd71eca..42e8dc24e5cb7b02639d4b80f831b8856f0f45d5 100644 ---- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -@@ -247,6 +247,7 @@ public class ExperienceOrb extends Entity { - } - - private static boolean tryMergeToExisting(ServerLevel world, Vec3 pos, int amount) { -+ // Paper - TODO some other event for this kind of merge - AABB axisalignedbb = AABB.ofSize(pos, 1.0D, 1.0D, 1.0D); - int j = world.getRandom().nextInt(40); - List list = world.getEntities(EntityTypeTest.forClass(ExperienceOrb.class), axisalignedbb, (entityexperienceorb) -> { -@@ -273,6 +274,11 @@ public class ExperienceOrb extends Entity { - } - - private void merge(ExperienceOrb other) { -+ // Paper start - call orb merge event -+ if (!new com.destroystokyo.paper.event.entity.ExperienceOrbMergeEvent((org.bukkit.entity.ExperienceOrb) this.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) other.getBukkitEntity()).callEvent()) { -+ return; -+ } -+ // Paper end - call orb merge event - this.count += other.count; - this.age = Math.min(this.age, other.age); - other.discard(EntityRemoveEvent.Cause.MERGE); // CraftBukkit - add Bukkit remove cause -@@ -366,7 +372,7 @@ public class ExperienceOrb extends Entity { - int l = amount - k * amount / j; - - if (l > 0) { -- this.value = l; // CraftBukkit - update exp value of orb for PlayerItemMendEvent calls -+ // 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 - return this.repairPlayerItems(player, l); - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java -index 5a7d314ec0562e472f5dc45924a7b24841cff126..650e4a01cecc4cc08e7ff9ebcc4c367084351f21 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java -@@ -18,6 +18,18 @@ public class CraftExperienceOrb extends CraftEntity implements ExperienceOrb { - this.getHandle().value = value; - } - -+ // Paper start - expose count -+ @Override -+ public int getCount() { -+ return this.getHandle().count; -+ } -+ -+ @Override -+ public void setCount(final int count) { -+ this.getHandle().count = count; -+ } -+ // Paper end -+ - // Paper start - public java.util.UUID getTriggerEntityId() { - return getHandle().triggerEntityId; -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index f482fc14e171129f9fa60113b1223b2db79ec6ec..b8e1a7251f9fa09f03b00b387013af1c623a1e52 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -712,15 +712,29 @@ public class CraftEventFactory { - if (entity instanceof net.minecraft.world.entity.ExperienceOrb xp) { - double radius = world.spigotConfig.expMerge; - if (radius > 0) { -+ // 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; -+ if (mergeUnconditionally || xp.value < maxValue) { // Paper - Skip iteration if unnecessary -+ - List entities = world.getEntities(entity, entity.getBoundingBox().inflate(radius, radius, radius)); - for (Entity e : entities) { - if (e instanceof net.minecraft.world.entity.ExperienceOrb loopItem) { -- if (!loopItem.isRemoved()) { -+ // Paper start -+ if (!loopItem.isRemoved() && xp.count == loopItem.count && (mergeUnconditionally || loopItem.value < maxValue) && new com.destroystokyo.paper.event.entity.ExperienceOrbMergeEvent((org.bukkit.entity.ExperienceOrb) entity.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) loopItem.getBukkitEntity()).callEvent()) { // Paper - ExperienceOrbMergeEvent -+ long newTotal = (long)xp.value + (long)loopItem.value; -+ if ((int) newTotal < 0) continue; // Overflow -+ if (!mergeUnconditionally && newTotal > maxValue) { -+ loopItem.value = (int) (newTotal - maxValue); -+ xp.value = (int) maxValue; -+ } else { - xp.value += loopItem.value; - loopItem.discard(null); // Add Bukkit remove cause -+ } // Paper end - Maximum exp value when merging - } - } - } -+ } // Paper end - End iteration skip check - All tweaking ends here - } - } - // Spigot end diff --git a/patches/server/0350-Fix-PotionEffect-ignores-icon-flag.patch b/patches/server/0350-Fix-PotionEffect-ignores-icon-flag.patch new file mode 100644 index 0000000000..6d08a4cd68 --- /dev/null +++ b/patches/server/0350-Fix-PotionEffect-ignores-icon-flag.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kickash32 +Date: Fri, 8 May 2020 00:49:18 -0400 +Subject: [PATCH] Fix PotionEffect ignores icon flag + +Co-authored-by: Tamion <70228790+notTamion@users.noreply.github.com> + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index c763d3524794a2505a6296917d34b6f7e737402d..1873b5c22d3b351b6120cb832c6ff045d9ad38f0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -494,7 +494,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + + @Override + public boolean addPotionEffect(PotionEffect effect, boolean force) { +- this.getHandle().addEffect(new MobEffectInstance(CraftPotionEffectType.bukkitToMinecraftHolder(effect.getType()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()), EntityPotionEffectEvent.Cause.PLUGIN); ++ this.getHandle().addEffect(org.bukkit.craftbukkit.potion.CraftPotionUtil.fromBukkit(effect), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon + return true; + } + +@@ -515,7 +515,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + @Override + public PotionEffect getPotionEffect(PotionEffectType type) { + MobEffectInstance handle = this.getHandle().getEffect(CraftPotionEffectType.bukkitToMinecraftHolder(type)); +- return (handle == null) ? null : new PotionEffect(CraftPotionEffectType.minecraftHolderToBukkit(handle.getEffect()), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible()); ++ return (handle == null) ? null : org.bukkit.craftbukkit.potion.CraftPotionUtil.toBukkit(handle); // Paper + } + + @Override +@@ -527,7 +527,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + public Collection getActivePotionEffects() { + List effects = new ArrayList(); + for (MobEffectInstance handle : this.getHandle().activeEffects.values()) { +- effects.add(new PotionEffect(CraftPotionEffectType.minecraftHolderToBukkit(handle.getEffect()), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible())); ++ effects.add(org.bukkit.craftbukkit.potion.CraftPotionUtil.toBukkit(handle)); // Paper + } + return effects; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java +index b7525f6ddc8f315ec9830b6b8f225d4839d306ad..01af4db5d0f17ea2943e5c464d4122a358503bc1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java ++++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java +@@ -78,7 +78,7 @@ public class CraftPotionUtil { + + public static MobEffectInstance fromBukkit(PotionEffect effect) { + Holder type = CraftPotionEffectType.bukkitToMinecraftHolder(effect.getType()); +- return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()); ++ return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()); // Paper + } + + public static PotionEffect toBukkit(MobEffectInstance effect) { +@@ -87,7 +87,7 @@ public class CraftPotionUtil { + int duration = effect.getDuration(); + boolean ambient = effect.isAmbient(); + boolean particles = effect.isVisible(); +- return new PotionEffect(type, duration, amp, ambient, particles); ++ return new PotionEffect(type, duration, amp, ambient, particles, effect.showIcon()); // Paper + } + + public static boolean equals(Holder mobEffect, PotionEffectType type) { diff --git a/patches/server/0351-Fix-PotionEffect-ignores-icon-flag.patch b/patches/server/0351-Fix-PotionEffect-ignores-icon-flag.patch deleted file mode 100644 index 6d08a4cd68..0000000000 --- a/patches/server/0351-Fix-PotionEffect-ignores-icon-flag.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: kickash32 -Date: Fri, 8 May 2020 00:49:18 -0400 -Subject: [PATCH] Fix PotionEffect ignores icon flag - -Co-authored-by: Tamion <70228790+notTamion@users.noreply.github.com> - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index c763d3524794a2505a6296917d34b6f7e737402d..1873b5c22d3b351b6120cb832c6ff045d9ad38f0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -494,7 +494,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - - @Override - public boolean addPotionEffect(PotionEffect effect, boolean force) { -- this.getHandle().addEffect(new MobEffectInstance(CraftPotionEffectType.bukkitToMinecraftHolder(effect.getType()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()), EntityPotionEffectEvent.Cause.PLUGIN); -+ this.getHandle().addEffect(org.bukkit.craftbukkit.potion.CraftPotionUtil.fromBukkit(effect), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon - return true; - } - -@@ -515,7 +515,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - @Override - public PotionEffect getPotionEffect(PotionEffectType type) { - MobEffectInstance handle = this.getHandle().getEffect(CraftPotionEffectType.bukkitToMinecraftHolder(type)); -- return (handle == null) ? null : new PotionEffect(CraftPotionEffectType.minecraftHolderToBukkit(handle.getEffect()), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible()); -+ return (handle == null) ? null : org.bukkit.craftbukkit.potion.CraftPotionUtil.toBukkit(handle); // Paper - } - - @Override -@@ -527,7 +527,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - public Collection getActivePotionEffects() { - List effects = new ArrayList(); - for (MobEffectInstance handle : this.getHandle().activeEffects.values()) { -- effects.add(new PotionEffect(CraftPotionEffectType.minecraftHolderToBukkit(handle.getEffect()), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible())); -+ effects.add(org.bukkit.craftbukkit.potion.CraftPotionUtil.toBukkit(handle)); // Paper - } - return effects; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java -index b7525f6ddc8f315ec9830b6b8f225d4839d306ad..01af4db5d0f17ea2943e5c464d4122a358503bc1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java -+++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java -@@ -78,7 +78,7 @@ public class CraftPotionUtil { - - public static MobEffectInstance fromBukkit(PotionEffect effect) { - Holder type = CraftPotionEffectType.bukkitToMinecraftHolder(effect.getType()); -- return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()); -+ return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()); // Paper - } - - public static PotionEffect toBukkit(MobEffectInstance effect) { -@@ -87,7 +87,7 @@ public class CraftPotionUtil { - int duration = effect.getDuration(); - boolean ambient = effect.isAmbient(); - boolean particles = effect.isVisible(); -- return new PotionEffect(type, duration, amp, ambient, particles); -+ return new PotionEffect(type, duration, amp, ambient, particles, effect.showIcon()); // Paper - } - - public static boolean equals(Holder mobEffect, PotionEffectType type) { diff --git a/patches/server/0351-Potential-bed-API.patch b/patches/server/0351-Potential-bed-API.patch new file mode 100644 index 0000000000..e4dbfa304f --- /dev/null +++ b/patches/server/0351-Potential-bed-API.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Sun, 10 May 2020 23:06:30 -0400 +Subject: [PATCH] Potential bed API + +Adds a new method to fetch the location of a player's bed without generating any sync loads. + +getPotentialBedLocation - Gets the last known location of a player's bed. This does not preform any check if the bed is still valid and does not load any chunks. + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +index 6ec6b80d224e2402054afb85b78c793942a58bbf..b2ab430392fc0f214ba8c5383e3f3ad5c548bda2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -130,6 +130,22 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + return this.getHandle().sleepCounter; + } + ++ // Paper start - Potential bed api ++ @Override ++ public Location getPotentialBedLocation() { ++ ServerPlayer handle = (ServerPlayer) getHandle(); ++ BlockPos bed = handle.getRespawnPosition(); ++ if (bed == null) { ++ return null; ++ } ++ ++ net.minecraft.server.level.ServerLevel worldServer = handle.server.getLevel(handle.getRespawnDimension()); ++ if (worldServer == null) { ++ return null; ++ } ++ return new Location(worldServer.getWorld(), bed.getX(), bed.getY(), bed.getZ()); ++ } ++ // Paper end + @Override + public boolean sleep(Location location, boolean force) { + Preconditions.checkArgument(location != null, "Location cannot be null"); diff --git a/patches/server/0352-Potential-bed-API.patch b/patches/server/0352-Potential-bed-API.patch deleted file mode 100644 index e4dbfa304f..0000000000 --- a/patches/server/0352-Potential-bed-API.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Sun, 10 May 2020 23:06:30 -0400 -Subject: [PATCH] Potential bed API - -Adds a new method to fetch the location of a player's bed without generating any sync loads. - -getPotentialBedLocation - Gets the last known location of a player's bed. This does not preform any check if the bed is still valid and does not load any chunks. - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 6ec6b80d224e2402054afb85b78c793942a58bbf..b2ab430392fc0f214ba8c5383e3f3ad5c548bda2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -130,6 +130,22 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - return this.getHandle().sleepCounter; - } - -+ // Paper start - Potential bed api -+ @Override -+ public Location getPotentialBedLocation() { -+ ServerPlayer handle = (ServerPlayer) getHandle(); -+ BlockPos bed = handle.getRespawnPosition(); -+ if (bed == null) { -+ return null; -+ } -+ -+ net.minecraft.server.level.ServerLevel worldServer = handle.server.getLevel(handle.getRespawnDimension()); -+ if (worldServer == null) { -+ return null; -+ } -+ return new Location(worldServer.getWorld(), bed.getX(), bed.getY(), bed.getZ()); -+ } -+ // Paper end - @Override - public boolean sleep(Location location, boolean force) { - Preconditions.checkArgument(location != null, "Location cannot be null"); diff --git a/patches/server/0352-Wait-for-Async-Tasks-during-shutdown.patch b/patches/server/0352-Wait-for-Async-Tasks-during-shutdown.patch new file mode 100644 index 0000000000..c5497b4e08 --- /dev/null +++ b/patches/server/0352-Wait-for-Async-Tasks-during-shutdown.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 10 May 2020 22:16:17 -0400 +Subject: [PATCH] Wait for Async Tasks during shutdown + +Server.reload() had this logic to give time for tasks to shutdown, +however shutdown did not... + +Adds a 5 second grace period for any async tasks to finish and warns +if any are still running after that delay just as reload does. + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 8e205796d0c9abbf01bf6ec191e2dfc7b972a0dd..84999223df47a9eccbcec4e1ea80786090d8d9c5 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -955,6 +955,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) { ++ try { ++ Thread.sleep(100); ++ } catch (InterruptedException e) {} ++ pollCount++; ++ } ++ ++ List overdueWorkers = getScheduler().getActiveWorkers(); ++ for (BukkitWorker worker : overdueWorkers) { ++ Plugin plugin = worker.getOwner(); ++ getLogger().log(Level.SEVERE, String.format( ++ "Nag author(s): '%s' of '%s' about the following: %s", ++ plugin.getPluginMeta().getAuthors(), ++ plugin.getPluginMeta().getDisplayName(), ++ "This plugin is not properly shutting down its async tasks when it is being shut down. This task may throw errors during the final shutdown logs and might not complete before process dies." ++ )); ++ if (console.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread(worker.getThread(), "still running"); // Paper - Debugging ++ } ++ } ++ // Paper end - Wait for Async Tasks during shutdown ++ + @Override + public void reloadData() { + ReloadCommand.reload(this.console); diff --git a/patches/server/0353-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch b/patches/server/0353-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch new file mode 100644 index 0000000000..60f62b1aef --- /dev/null +++ b/patches/server/0353-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kickash32 +Date: Sat, 9 May 2020 02:01:48 -0400 +Subject: [PATCH] Ensure EntityRaider respects game and entity rules for + picking up items + + +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 0fb8779648c9c4ead7ffcc24781a6644a855b65b..b6f1d989df3811f423d1cdff98b05ecc4a9268fe 100644 +--- a/src/main/java/net/minecraft/world/entity/raid/Raider.java ++++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java +@@ -338,6 +338,7 @@ public abstract class Raider extends PatrollingMonster { + } + + private boolean cannotPickUpBanner() { ++ if (!getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items + if (!this.mob.hasActiveRaid()) { + return true; + } else if (this.mob.getCurrentRaid().isOver()) { diff --git a/patches/server/0353-Wait-for-Async-Tasks-during-shutdown.patch b/patches/server/0353-Wait-for-Async-Tasks-during-shutdown.patch deleted file mode 100644 index c5497b4e08..0000000000 --- a/patches/server/0353-Wait-for-Async-Tasks-during-shutdown.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 10 May 2020 22:16:17 -0400 -Subject: [PATCH] Wait for Async Tasks during shutdown - -Server.reload() had this logic to give time for tasks to shutdown, -however shutdown did not... - -Adds a 5 second grace period for any async tasks to finish and warns -if any are still running after that delay just as reload does. - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 8e205796d0c9abbf01bf6ec191e2dfc7b972a0dd..84999223df47a9eccbcec4e1ea80786090d8d9c5 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -955,6 +955,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) { -+ try { -+ Thread.sleep(100); -+ } catch (InterruptedException e) {} -+ pollCount++; -+ } -+ -+ List overdueWorkers = getScheduler().getActiveWorkers(); -+ for (BukkitWorker worker : overdueWorkers) { -+ Plugin plugin = worker.getOwner(); -+ getLogger().log(Level.SEVERE, String.format( -+ "Nag author(s): '%s' of '%s' about the following: %s", -+ plugin.getPluginMeta().getAuthors(), -+ plugin.getPluginMeta().getDisplayName(), -+ "This plugin is not properly shutting down its async tasks when it is being shut down. This task may throw errors during the final shutdown logs and might not complete before process dies." -+ )); -+ if (console.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread(worker.getThread(), "still running"); // Paper - Debugging -+ } -+ } -+ // Paper end - Wait for Async Tasks during shutdown -+ - @Override - public void reloadData() { - ReloadCommand.reload(this.console); diff --git a/patches/server/0354-Add-option-for-console-having-all-permissions.patch b/patches/server/0354-Add-option-for-console-having-all-permissions.patch new file mode 100644 index 0000000000..ace91d22dd --- /dev/null +++ b/patches/server/0354-Add-option-for-console-having-all-permissions.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 16 May 2020 10:12:15 +0200 +Subject: [PATCH] Add option for console having all permissions + + +diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java +index 324e6d1a4fadd3e557e4ba05f04e6a5891cc54df..4e56018b64d11f76c8da43fd8f85c6de72204e36 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java +@@ -93,5 +93,15 @@ public class CraftConsoleCommandSender extends ServerCommandSender implements Co + public void sendMessage(final net.kyori.adventure.identity.Identity identity, final net.kyori.adventure.text.Component message, final net.kyori.adventure.audience.MessageType type) { + this.sendRawMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); + } ++ ++ @Override ++ public boolean hasPermission(String name) { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name); ++ } ++ ++ @Override ++ public boolean hasPermission(org.bukkit.permissions.Permission perm) { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java +index 5b7d230103f421fb939072e1526854f715430e51..b5e325a7b2d3f49299b35e233ed6539b5bfc3465 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java +@@ -55,4 +55,16 @@ public class CraftRemoteConsoleCommandSender extends ServerCommandSender impleme + public void setOp(boolean value) { + throw new UnsupportedOperationException("Cannot change operator status of remote controller."); + } ++ ++ // Paper start ++ @Override ++ public boolean hasPermission(String name) { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name); ++ } ++ ++ @Override ++ public boolean hasPermission(org.bukkit.permissions.Permission perm) { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm); ++ } ++ // Paper end + } diff --git a/patches/server/0354-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch b/patches/server/0354-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch deleted file mode 100644 index 60f62b1aef..0000000000 --- a/patches/server/0354-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: kickash32 -Date: Sat, 9 May 2020 02:01:48 -0400 -Subject: [PATCH] Ensure EntityRaider respects game and entity rules for - picking up items - - -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 0fb8779648c9c4ead7ffcc24781a6644a855b65b..b6f1d989df3811f423d1cdff98b05ecc4a9268fe 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raider.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java -@@ -338,6 +338,7 @@ public abstract class Raider extends PatrollingMonster { - } - - private boolean cannotPickUpBanner() { -+ if (!getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items - if (!this.mob.hasActiveRaid()) { - return true; - } else if (this.mob.getCurrentRaid().isOver()) { diff --git a/patches/server/0355-Add-option-for-console-having-all-permissions.patch b/patches/server/0355-Add-option-for-console-having-all-permissions.patch deleted file mode 100644 index ace91d22dd..0000000000 --- a/patches/server/0355-Add-option-for-console-having-all-permissions.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 16 May 2020 10:12:15 +0200 -Subject: [PATCH] Add option for console having all permissions - - -diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java -index 324e6d1a4fadd3e557e4ba05f04e6a5891cc54df..4e56018b64d11f76c8da43fd8f85c6de72204e36 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java -@@ -93,5 +93,15 @@ public class CraftConsoleCommandSender extends ServerCommandSender implements Co - public void sendMessage(final net.kyori.adventure.identity.Identity identity, final net.kyori.adventure.text.Component message, final net.kyori.adventure.audience.MessageType type) { - this.sendRawMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); - } -+ -+ @Override -+ public boolean hasPermission(String name) { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name); -+ } -+ -+ @Override -+ public boolean hasPermission(org.bukkit.permissions.Permission perm) { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java -index 5b7d230103f421fb939072e1526854f715430e51..b5e325a7b2d3f49299b35e233ed6539b5bfc3465 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java -@@ -55,4 +55,16 @@ public class CraftRemoteConsoleCommandSender extends ServerCommandSender impleme - public void setOp(boolean value) { - throw new UnsupportedOperationException("Cannot change operator status of remote controller."); - } -+ -+ // Paper start -+ @Override -+ public boolean hasPermission(String name) { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name); -+ } -+ -+ @Override -+ public boolean hasPermission(org.bukkit.permissions.Permission perm) { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm); -+ } -+ // Paper end - } diff --git a/patches/server/0355-Fix-villager-trading-demand-MC-163962.patch b/patches/server/0355-Fix-villager-trading-demand-MC-163962.patch new file mode 100644 index 0000000000..bd7b6c4273 --- /dev/null +++ b/patches/server/0355-Fix-villager-trading-demand-MC-163962.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chickeneer +Date: Fri, 5 Jun 2020 20:02:04 -0500 +Subject: [PATCH] Fix villager trading demand - MC-163962 + +Prevent demand from going negative and tending to negative infinity + +diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java +index 44808589939afe50d8294269b7da12019acd2690..89982d25f60c8b60ba91e559ef88278f338fe215 100644 +--- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java ++++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java +@@ -124,7 +124,7 @@ public class MerchantOffer { + } + + public void updateDemand() { +- this.demand = this.demand + this.uses - (this.maxUses - this.uses); ++ this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962 + } + + public ItemStack assemble() { diff --git a/patches/server/0356-Fix-villager-trading-demand-MC-163962.patch b/patches/server/0356-Fix-villager-trading-demand-MC-163962.patch deleted file mode 100644 index bd7b6c4273..0000000000 --- a/patches/server/0356-Fix-villager-trading-demand-MC-163962.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: chickeneer -Date: Fri, 5 Jun 2020 20:02:04 -0500 -Subject: [PATCH] Fix villager trading demand - MC-163962 - -Prevent demand from going negative and tending to negative infinity - -diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -index 44808589939afe50d8294269b7da12019acd2690..89982d25f60c8b60ba91e559ef88278f338fe215 100644 ---- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -+++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -@@ -124,7 +124,7 @@ public class MerchantOffer { - } - - public void updateDemand() { -- this.demand = this.demand + this.uses - (this.maxUses - this.uses); -+ this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962 - } - - public ItemStack assemble() { diff --git a/patches/server/0356-Maps-shouldn-t-load-chunks.patch b/patches/server/0356-Maps-shouldn-t-load-chunks.patch new file mode 100644 index 0000000000..5466a9cdef --- /dev/null +++ b/patches/server/0356-Maps-shouldn-t-load-chunks.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 +Date: Sun, 7 Jun 2020 21:43:42 +0100 +Subject: [PATCH] Maps shouldn't load chunks + +Previously maps would load all chunks in a certain radius depending on + their scale when trying to update their content. This would result in + main thread chunk loads when they weren't really necessary, especially + on low view distances or "slow" async chunk loads after teleports or + other prioritisation. + + This changes it to only try to render already loaded chunks based on + the assumption that the chunks around the player will get loaded + eventually anyways and that maps will get checked for update every + five ticks that movement occur in anyways. + +diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java +index 9780a719773480e20b667b753983e804127b73cd..adec25694820189b6f77913db1bf7c581458d2ab 100644 +--- a/src/main/java/net/minecraft/world/item/MapItem.java ++++ b/src/main/java/net/minecraft/world/item/MapItem.java +@@ -97,8 +97,8 @@ public class MapItem extends Item { + int r = (j / i + o - 64) * i; + int s = (k / i + p - 64) * i; + Multiset multiset = LinkedHashMultiset.create(); +- LevelChunk levelChunk = world.getChunk(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s)); +- if (!levelChunk.isEmpty()) { ++ LevelChunk levelChunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s)); // Paper - Maps shouldn't load chunks ++ if (levelChunk != null && !levelChunk.isEmpty()) { // Paper - Maps shouldn't load chunks + int t = 0; + double e = 0.0; + if (world.dimensionType().hasCeiling()) { diff --git a/patches/server/0357-Maps-shouldn-t-load-chunks.patch b/patches/server/0357-Maps-shouldn-t-load-chunks.patch deleted file mode 100644 index 5466a9cdef..0000000000 --- a/patches/server/0357-Maps-shouldn-t-load-chunks.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Sun, 7 Jun 2020 21:43:42 +0100 -Subject: [PATCH] Maps shouldn't load chunks - -Previously maps would load all chunks in a certain radius depending on - their scale when trying to update their content. This would result in - main thread chunk loads when they weren't really necessary, especially - on low view distances or "slow" async chunk loads after teleports or - other prioritisation. - - This changes it to only try to render already loaded chunks based on - the assumption that the chunks around the player will get loaded - eventually anyways and that maps will get checked for update every - five ticks that movement occur in anyways. - -diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java -index 9780a719773480e20b667b753983e804127b73cd..adec25694820189b6f77913db1bf7c581458d2ab 100644 ---- a/src/main/java/net/minecraft/world/item/MapItem.java -+++ b/src/main/java/net/minecraft/world/item/MapItem.java -@@ -97,8 +97,8 @@ public class MapItem extends Item { - int r = (j / i + o - 64) * i; - int s = (k / i + p - 64) * i; - Multiset multiset = LinkedHashMultiset.create(); -- LevelChunk levelChunk = world.getChunk(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s)); -- if (!levelChunk.isEmpty()) { -+ LevelChunk levelChunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s)); // Paper - Maps shouldn't load chunks -+ if (levelChunk != null && !levelChunk.isEmpty()) { // Paper - Maps shouldn't load chunks - int t = 0; - double e = 0.0; - if (world.dimensionType().hasCeiling()) { diff --git a/patches/server/0357-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch b/patches/server/0357-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch new file mode 100644 index 0000000000..a9541d0791 --- /dev/null +++ b/patches/server/0357-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 7 Jun 2020 19:25:13 -0400 +Subject: [PATCH] Use seed based lookup for Treasure Maps - Fixes lag from + carto/sunken maps + + +diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java +index adec25694820189b6f77913db1bf7c581458d2ab..8ff50a4c7461bbd9f469d503f6b5ee482d2463d7 100644 +--- a/src/main/java/net/minecraft/world/item/MapItem.java ++++ b/src/main/java/net/minecraft/world/item/MapItem.java +@@ -205,7 +205,7 @@ public class MapItem extends Item { + + for (int n = 0; n < 128; n++) { + for (int o = 0; o < 128; o++) { +- Holder holder = world.getBiome(mutableBlockPos.set((l + o) * i, 0, (m + n) * i)); ++ Holder holder = world.getUncachedNoiseBiome((l + o) * i, 0, (m + n) * i); // Paper - Perf: Use seed based lookup for treasure maps + bls[n * 128 + o] = holder.is(BiomeTags.WATER_ON_MAP_OUTLINES); + } + } diff --git a/patches/server/0358-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch b/patches/server/0358-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch new file mode 100644 index 0000000000..2b6515bcf7 --- /dev/null +++ b/patches/server/0358-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: ossi +Date: Fri, 12 Jun 2020 01:38:06 +0300 +Subject: [PATCH] Fix CraftScheduler#runTaskTimerAsynchronously(Plugin, + Consumer, long, long) scheduling a non-repeating task instead of + a repeating one. + + +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +index 4f2eafbc012b7f9bdbe409d266fdb467ec788de6..20760e08b3d9aba86969b886b46deec5b125bf1f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +@@ -196,7 +196,7 @@ public class CraftScheduler implements BukkitScheduler { + + @Override + public void runTaskTimerAsynchronously(Plugin plugin, Consumer task, long delay, long period) throws IllegalArgumentException { +- this.runTaskTimerAsynchronously(plugin, (Object) task, delay, CraftTask.NO_REPEATING); ++ this.runTaskTimerAsynchronously(plugin, (Object) task, delay, period); // Paper + } + + @Override diff --git a/patches/server/0358-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch b/patches/server/0358-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch deleted file mode 100644 index a9541d0791..0000000000 --- a/patches/server/0358-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 7 Jun 2020 19:25:13 -0400 -Subject: [PATCH] Use seed based lookup for Treasure Maps - Fixes lag from - carto/sunken maps - - -diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java -index adec25694820189b6f77913db1bf7c581458d2ab..8ff50a4c7461bbd9f469d503f6b5ee482d2463d7 100644 ---- a/src/main/java/net/minecraft/world/item/MapItem.java -+++ b/src/main/java/net/minecraft/world/item/MapItem.java -@@ -205,7 +205,7 @@ public class MapItem extends Item { - - for (int n = 0; n < 128; n++) { - for (int o = 0; o < 128; o++) { -- Holder holder = world.getBiome(mutableBlockPos.set((l + o) * i, 0, (m + n) * i)); -+ Holder holder = world.getUncachedNoiseBiome((l + o) * i, 0, (m + n) * i); // Paper - Perf: Use seed based lookup for treasure maps - bls[n * 128 + o] = holder.is(BiomeTags.WATER_ON_MAP_OUTLINES); - } - } diff --git a/patches/server/0359-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch b/patches/server/0359-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch deleted file mode 100644 index 2b6515bcf7..0000000000 --- a/patches/server/0359-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: ossi -Date: Fri, 12 Jun 2020 01:38:06 +0300 -Subject: [PATCH] Fix CraftScheduler#runTaskTimerAsynchronously(Plugin, - Consumer, long, long) scheduling a non-repeating task instead of - a repeating one. - - -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index 4f2eafbc012b7f9bdbe409d266fdb467ec788de6..20760e08b3d9aba86969b886b46deec5b125bf1f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -196,7 +196,7 @@ public class CraftScheduler implements BukkitScheduler { - - @Override - public void runTaskTimerAsynchronously(Plugin plugin, Consumer task, long delay, long period) throws IllegalArgumentException { -- this.runTaskTimerAsynchronously(plugin, (Object) task, delay, CraftTask.NO_REPEATING); -+ this.runTaskTimerAsynchronously(plugin, (Object) task, delay, period); // Paper - } - - @Override diff --git a/patches/server/0359-Fix-piston-physics-inconsistency-MC-188840.patch b/patches/server/0359-Fix-piston-physics-inconsistency-MC-188840.patch new file mode 100644 index 0000000000..aca7ba66df --- /dev/null +++ b/patches/server/0359-Fix-piston-physics-inconsistency-MC-188840.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Thu, 11 Jun 2020 17:29:42 -0700 +Subject: [PATCH] Fix piston physics inconsistency - MC-188840 + +Pistons invoke physics when they move blocks. The physics can cause +tnt blocks to ignite. However, pistons (when storing the blocks they "moved") +don't actually go back to the world state sometimes to check if something +like that happened. As a result they end up moving the tnt like it was +never ignited. This resulted in the ability to create machines +that can duplicate tnt, called "world eaters". +This patch makes the piston logic retrieve the block state from the world +prevent this from occuring. + +This patch also sets the moved pos to air immediately after creating +the moving piston TE. This prevents the block from being updated from +other physics calls by the piston. + +Tested against the following tnt duper design: +https://www.youtube.com/watch?v=mS7xxNGhjxs + +This patch also affects every type of machine that utilises +this mechanic. For example, dead coral is removed by a physics +update when being moved while it is attached to slimeblocks. + +Standard piston machines that don't destroy or modify the +blocks they move by physics updates should be entirely +unaffected. + +This patch fixes https://bugs.mojang.com/browse/MC-188840 + +This patch also fixes rail duping and carpet duping. + +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 0b80940ed23a35e0412957a50d04907b676b0aca..0c6b517196d48ba4384eac240b7e580adfdbc4d4 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 +@@ -419,13 +419,25 @@ public class PistonBaseBlock extends DirectionalBlock { + BlockState iblockdata2; + + for (j = list.size() - 1; j >= 0; --j) { +- blockposition3 = (BlockPos) list.get(j); +- iblockdata1 = world.getBlockState(blockposition3); ++ // Paper start - fix a variety of piston desync dupes ++ boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication; ++ BlockPos oldPos = blockposition3 = (BlockPos) list.get(j); ++ iblockdata1 = allowDesync ? world.getBlockState(oldPos) : null; ++ // Paper end - fix a variety of piston desync dupes + blockposition3 = blockposition3.relative(enumdirection1); + map.remove(blockposition3); + iblockdata2 = (BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(PistonBaseBlock.FACING, dir); + world.setBlock(blockposition3, iblockdata2, 68); +- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, (BlockState) list1.get(j), dir, extend, false)); ++ // Paper start - fix a variety of piston desync dupes ++ if (!allowDesync) { ++ iblockdata1 = world.getBlockState(oldPos); ++ map.replace(oldPos, iblockdata1); ++ } ++ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, allowDesync ? (BlockState) list1.get(j) : iblockdata1, dir, extend, false)); ++ if (!allowDesync) { ++ world.setBlock(oldPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_MOVE_BY_PISTON | 1024); // set air to prevent later physics updates from seeing this block ++ } ++ // Paper end - fix a variety of piston desync dupes + aiblockdata[i++] = iblockdata1; + } + +diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java +index 53d0057e123540162852cb10fba1b7f7ac8388ad..46afba838cf12eeb1bbccaa260131a76f090364b 100644 +--- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java +@@ -306,7 +306,7 @@ public class PistonMovingBlockEntity extends BlockEntity { + if (world.getBlockState(pos).is(Blocks.MOVING_PISTON)) { + BlockState blockState = Block.updateFromNeighbourShapes(blockEntity.movedState, world, pos); + if (blockState.isAir()) { +- world.setBlock(pos, blockEntity.movedState, 84); ++ world.setBlock(pos, blockEntity.movedState, io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 84 : (84 | Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air + Block.updateOrDestroy(blockEntity.movedState, blockState, world, pos, 3); + } else { + if (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED)) { diff --git a/patches/server/0360-Fix-missing-chunks-due-to-integer-overflow.patch b/patches/server/0360-Fix-missing-chunks-due-to-integer-overflow.patch new file mode 100644 index 0000000000..e7af97469b --- /dev/null +++ b/patches/server/0360-Fix-missing-chunks-due-to-integer-overflow.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Slovikosky +Date: Tue, 9 Jun 2020 00:10:03 -0700 +Subject: [PATCH] Fix missing chunks due to integer overflow + +This patch fixes a bug in the EndIslandDensityFunction class where the distance +from 0,0 squared overflows the maximum size of an integer. The overflow leads +to hard chunk borders around 370,000 blocks from 0,0. After this cutoff there +is a few hundred thousand block gap before end land resuming to generate at +530,000 blocks from spawn. This is due to the integer flipping back and forth. + +The fix for the issue is quite simple, casting chunk coordinates to longs +allows the distance calculation to avoid overflow and work as intended. + +This issue is being tracked in Mojira ticket MC-159283 + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java +index 6171d57a0e5d1aecadfb2c23a72a92d897ca41ee..b09bc1dac649ce9f4826edc1923c843804226993 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java +@@ -521,7 +521,7 @@ public final class DensityFunctions { + int j = z / 2; + int k = x % 2; + int l = z % 2; +- float f = 100.0F - Mth.sqrt((float)(x * x + z * z)) * 8.0F; ++ float f = 100.0F - Mth.sqrt((long) x * (long) x + (long) z * (long) z) * 8.0F; // Paper - cast ints to long to avoid integer overflow + f = Mth.clamp(f, -100.0F, 80.0F); + + for (int m = -12; m <= 12; m++) { diff --git a/patches/server/0360-Fix-piston-physics-inconsistency-MC-188840.patch b/patches/server/0360-Fix-piston-physics-inconsistency-MC-188840.patch deleted file mode 100644 index aca7ba66df..0000000000 --- a/patches/server/0360-Fix-piston-physics-inconsistency-MC-188840.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Thu, 11 Jun 2020 17:29:42 -0700 -Subject: [PATCH] Fix piston physics inconsistency - MC-188840 - -Pistons invoke physics when they move blocks. The physics can cause -tnt blocks to ignite. However, pistons (when storing the blocks they "moved") -don't actually go back to the world state sometimes to check if something -like that happened. As a result they end up moving the tnt like it was -never ignited. This resulted in the ability to create machines -that can duplicate tnt, called "world eaters". -This patch makes the piston logic retrieve the block state from the world -prevent this from occuring. - -This patch also sets the moved pos to air immediately after creating -the moving piston TE. This prevents the block from being updated from -other physics calls by the piston. - -Tested against the following tnt duper design: -https://www.youtube.com/watch?v=mS7xxNGhjxs - -This patch also affects every type of machine that utilises -this mechanic. For example, dead coral is removed by a physics -update when being moved while it is attached to slimeblocks. - -Standard piston machines that don't destroy or modify the -blocks they move by physics updates should be entirely -unaffected. - -This patch fixes https://bugs.mojang.com/browse/MC-188840 - -This patch also fixes rail duping and carpet duping. - -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 0b80940ed23a35e0412957a50d04907b676b0aca..0c6b517196d48ba4384eac240b7e580adfdbc4d4 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 -@@ -419,13 +419,25 @@ public class PistonBaseBlock extends DirectionalBlock { - BlockState iblockdata2; - - for (j = list.size() - 1; j >= 0; --j) { -- blockposition3 = (BlockPos) list.get(j); -- iblockdata1 = world.getBlockState(blockposition3); -+ // Paper start - fix a variety of piston desync dupes -+ boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication; -+ BlockPos oldPos = blockposition3 = (BlockPos) list.get(j); -+ iblockdata1 = allowDesync ? world.getBlockState(oldPos) : null; -+ // Paper end - fix a variety of piston desync dupes - blockposition3 = blockposition3.relative(enumdirection1); - map.remove(blockposition3); - iblockdata2 = (BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(PistonBaseBlock.FACING, dir); - world.setBlock(blockposition3, iblockdata2, 68); -- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, (BlockState) list1.get(j), dir, extend, false)); -+ // Paper start - fix a variety of piston desync dupes -+ if (!allowDesync) { -+ iblockdata1 = world.getBlockState(oldPos); -+ map.replace(oldPos, iblockdata1); -+ } -+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, allowDesync ? (BlockState) list1.get(j) : iblockdata1, dir, extend, false)); -+ if (!allowDesync) { -+ world.setBlock(oldPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_MOVE_BY_PISTON | 1024); // set air to prevent later physics updates from seeing this block -+ } -+ // Paper end - fix a variety of piston desync dupes - aiblockdata[i++] = iblockdata1; - } - -diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java -index 53d0057e123540162852cb10fba1b7f7ac8388ad..46afba838cf12eeb1bbccaa260131a76f090364b 100644 ---- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java -@@ -306,7 +306,7 @@ public class PistonMovingBlockEntity extends BlockEntity { - if (world.getBlockState(pos).is(Blocks.MOVING_PISTON)) { - BlockState blockState = Block.updateFromNeighbourShapes(blockEntity.movedState, world, pos); - if (blockState.isAir()) { -- world.setBlock(pos, blockEntity.movedState, 84); -+ world.setBlock(pos, blockEntity.movedState, io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 84 : (84 | Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air - Block.updateOrDestroy(blockEntity.movedState, blockState, world, pos, 3); - } else { - if (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED)) { diff --git a/patches/server/0361-Fix-missing-chunks-due-to-integer-overflow.patch b/patches/server/0361-Fix-missing-chunks-due-to-integer-overflow.patch deleted file mode 100644 index e7af97469b..0000000000 --- a/patches/server/0361-Fix-missing-chunks-due-to-integer-overflow.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: David Slovikosky -Date: Tue, 9 Jun 2020 00:10:03 -0700 -Subject: [PATCH] Fix missing chunks due to integer overflow - -This patch fixes a bug in the EndIslandDensityFunction class where the distance -from 0,0 squared overflows the maximum size of an integer. The overflow leads -to hard chunk borders around 370,000 blocks from 0,0. After this cutoff there -is a few hundred thousand block gap before end land resuming to generate at -530,000 blocks from spawn. This is due to the integer flipping back and forth. - -The fix for the issue is quite simple, casting chunk coordinates to longs -allows the distance calculation to avoid overflow and work as intended. - -This issue is being tracked in Mojira ticket MC-159283 - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java -index 6171d57a0e5d1aecadfb2c23a72a92d897ca41ee..b09bc1dac649ce9f4826edc1923c843804226993 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java -@@ -521,7 +521,7 @@ public final class DensityFunctions { - int j = z / 2; - int k = x % 2; - int l = z % 2; -- float f = 100.0F - Mth.sqrt((float)(x * x + z * z)) * 8.0F; -+ float f = 100.0F - Mth.sqrt((long) x * (long) x + (long) z * (long) z) * 8.0F; // Paper - cast ints to long to avoid integer overflow - f = Mth.clamp(f, -100.0F, 80.0F); - - for (int m = -12; m <= 12; m++) { diff --git a/patches/server/0361-Prevent-position-desync-causing-tp-exploit.patch b/patches/server/0361-Prevent-position-desync-causing-tp-exploit.patch new file mode 100644 index 0000000000..f73360e724 --- /dev/null +++ b/patches/server/0361-Prevent-position-desync-causing-tp-exploit.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Fri, 12 Jun 2020 16:51:39 -0700 +Subject: [PATCH] Prevent position desync causing tp exploit + +Caused the server to revert to the player's overworld coordinates +after teleporting into the end. + +Sidenote: The underlying issue is that the move call can teleport +entities and do other things like kill the entity. In the future, +to fix all exploits derieved from this usually unexpected +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 517c215d47737c551125dec785de2896560f4cb0..9229caf16997e8bd6da6fae1532372827ec80291 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1413,6 +1413,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8)); + this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move ++ // Paper start - prevent position desync ++ if (this.awaitingPositionFromClient != null) { ++ return; // ... thanks Mojang for letting move calls teleport across dimensions. ++ } ++ // Paper end - prevent position desync + double d11 = d7; + + d6 = d0 - this.player.getX(); diff --git a/patches/server/0362-Inventory-getHolder-method-without-block-snapshot.patch b/patches/server/0362-Inventory-getHolder-method-without-block-snapshot.patch new file mode 100644 index 0000000000..e5f25132df --- /dev/null +++ b/patches/server/0362-Inventory-getHolder-method-without-block-snapshot.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 +Date: Wed, 10 Jun 2020 23:55:15 +0100 +Subject: [PATCH] Inventory getHolder method without block snapshot + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +index 628e0cffa6cac6da137a25b85e86a50aec59c4b4..f3a1859a1c2adb0448186c322793585dafefe7e0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +@@ -531,6 +531,13 @@ public class CraftInventory implements Inventory { + return this.inventory.getOwner(); + } + ++ // Paper start - getHolder without snapshot ++ @Override ++ public InventoryHolder getHolder(boolean useSnapshot) { ++ return inventory instanceof net.minecraft.world.level.block.entity.BlockEntity ? ((net.minecraft.world.level.block.entity.BlockEntity) inventory).getOwner(useSnapshot) : getHolder(); ++ } ++ // Paper end ++ + @Override + public int getMaxStackSize() { + return this.inventory.getMaxStackSize(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java +index c00c787a73b0796b645667427666b7ec4e333992..c3e2c9e2c3cbec2eda38096b6482bac1a0ea1dce 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java +@@ -63,6 +63,13 @@ public class CraftInventoryDoubleChest extends CraftInventory implements DoubleC + return new DoubleChest(this); + } + ++ // Paper start - getHolder without snapshot ++ @Override ++ public DoubleChest getHolder(boolean useSnapshot) { ++ return getHolder(); ++ } ++ // Paper end ++ + @Override + public Location getLocation() { + return this.getLeftSide().getLocation().add(this.getRightSide().getLocation()).multiply(0.5); diff --git a/patches/server/0362-Prevent-position-desync-causing-tp-exploit.patch b/patches/server/0362-Prevent-position-desync-causing-tp-exploit.patch deleted file mode 100644 index f73360e724..0000000000 --- a/patches/server/0362-Prevent-position-desync-causing-tp-exploit.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Fri, 12 Jun 2020 16:51:39 -0700 -Subject: [PATCH] Prevent position desync causing tp exploit - -Caused the server to revert to the player's overworld coordinates -after teleporting into the end. - -Sidenote: The underlying issue is that the move call can teleport -entities and do other things like kill the entity. In the future, -to fix all exploits derieved from this usually unexpected -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 517c215d47737c551125dec785de2896560f4cb0..9229caf16997e8bd6da6fae1532372827ec80291 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1413,6 +1413,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8)); - this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move -+ // Paper start - prevent position desync -+ if (this.awaitingPositionFromClient != null) { -+ return; // ... thanks Mojang for letting move calls teleport across dimensions. -+ } -+ // Paper end - prevent position desync - double d11 = d7; - - d6 = d0 - this.player.getX(); diff --git a/patches/server/0363-Add-PlayerRecipeBookClickEvent.patch b/patches/server/0363-Add-PlayerRecipeBookClickEvent.patch new file mode 100644 index 0000000000..58ea92d25f --- /dev/null +++ b/patches/server/0363-Add-PlayerRecipeBookClickEvent.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Fri, 5 Jun 2020 18:24:06 -0400 +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 9229caf16997e8bd6da6fae1532372827ec80291..8570b0ecd2a0db9bb02ebcd12bafa1af31bf4b45 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -201,6 +201,7 @@ import net.minecraft.world.phys.Vec3; + import net.minecraft.world.phys.shapes.BooleanOp; + import net.minecraft.world.phys.shapes.Shapes; + import net.minecraft.world.phys.shapes.VoxelShape; ++import org.bukkit.NamespacedKey; + import org.slf4j.Logger; + + // CraftBukkit start +@@ -3157,21 +3158,41 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + ServerGamePacketListenerImpl.LOGGER.debug("Player {} tried to place impossible recipe {}", this.player, recipeholder.id().location()); + return; + } ++ // Paper start - Add PlayerRecipeBookClickEvent ++ NamespacedKey recipeName = org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(recipeholder.id().location()); ++ boolean makeAll = packet.useMaxItems(); ++ com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent paperEvent = new com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent( ++ this.player.getBukkitEntity(), recipeName, makeAll ++ ); ++ if (!paperEvent.callEvent()) { ++ return; ++ } ++ recipeName = paperEvent.getRecipe(); ++ makeAll = paperEvent.isMakeAll(); ++ if (org.bukkit.event.player.PlayerRecipeBookClickEvent.getHandlerList().getRegisteredListeners().length > 0) { ++ // Paper end - Add PlayerRecipeBookClickEvent + + // CraftBukkit start - implement PlayerRecipeBookClickEvent +- org.bukkit.inventory.Recipe recipe = recipeholder.toBukkitRecipe(); ++ org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(recipeName); // Paper - Add PlayerRecipeBookClickEvent - forward to legacy event + if (recipe == null) { + return; + } +- org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, packet.useMaxItems()); ++ // Paper start - Add PlayerRecipeBookClickEvent - forward to legacy event ++ org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, makeAll); ++ recipeName = ((org.bukkit.Keyed) event.getRecipe()).getKey(); ++ makeAll = event.isShiftClick(); ++ } ++ if (!(this.player.containerMenu instanceof RecipeBookMenu)) { ++ return; ++ } ++ // Paper end - Add PlayerRecipeBookClickEvent - forward to legacy event + + // Cast to keyed should be safe as the recipe will never be a MerchantRecipe. +- recipeholder = this.server.getRecipeManager().byKey(CraftRecipe.toMinecraft(((org.bukkit.Keyed) event.getRecipe()).getKey())).orElse(null); ++ recipeholder = this.server.getRecipeManager().byKey(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.RECIPE, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(recipeName))).orElse(null); // Paper - Add PlayerRecipeBookClickEvent - forward to legacy event + if (recipeholder == null) { + return; + } +- +- RecipeBookMenu.PostPlaceAction containerrecipebook_a = containerrecipebook.handlePlacement(event.isShiftClick(), this.player.isCreative(), recipeholder, this.player.serverLevel(), this.player.getInventory()); ++ RecipeBookMenu.PostPlaceAction containerrecipebook_a = containerrecipebook.handlePlacement(makeAll, this.player.isCreative(), recipeholder, this.player.serverLevel(), this.player.getInventory()); + // CraftBukkit end + + if (containerrecipebook_a == RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE) { diff --git a/patches/server/0363-Inventory-getHolder-method-without-block-snapshot.patch b/patches/server/0363-Inventory-getHolder-method-without-block-snapshot.patch deleted file mode 100644 index e5f25132df..0000000000 --- a/patches/server/0363-Inventory-getHolder-method-without-block-snapshot.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Wed, 10 Jun 2020 23:55:15 +0100 -Subject: [PATCH] Inventory getHolder method without block snapshot - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -index 628e0cffa6cac6da137a25b85e86a50aec59c4b4..f3a1859a1c2adb0448186c322793585dafefe7e0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -@@ -531,6 +531,13 @@ public class CraftInventory implements Inventory { - return this.inventory.getOwner(); - } - -+ // Paper start - getHolder without snapshot -+ @Override -+ public InventoryHolder getHolder(boolean useSnapshot) { -+ return inventory instanceof net.minecraft.world.level.block.entity.BlockEntity ? ((net.minecraft.world.level.block.entity.BlockEntity) inventory).getOwner(useSnapshot) : getHolder(); -+ } -+ // Paper end -+ - @Override - public int getMaxStackSize() { - return this.inventory.getMaxStackSize(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java -index c00c787a73b0796b645667427666b7ec4e333992..c3e2c9e2c3cbec2eda38096b6482bac1a0ea1dce 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java -@@ -63,6 +63,13 @@ public class CraftInventoryDoubleChest extends CraftInventory implements DoubleC - return new DoubleChest(this); - } - -+ // Paper start - getHolder without snapshot -+ @Override -+ public DoubleChest getHolder(boolean useSnapshot) { -+ return getHolder(); -+ } -+ // Paper end -+ - @Override - public Location getLocation() { - return this.getLeftSide().getLocation().add(this.getRightSide().getLocation()).multiply(0.5); diff --git a/patches/server/0364-Add-PlayerRecipeBookClickEvent.patch b/patches/server/0364-Add-PlayerRecipeBookClickEvent.patch deleted file mode 100644 index 58ea92d25f..0000000000 --- a/patches/server/0364-Add-PlayerRecipeBookClickEvent.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Fri, 5 Jun 2020 18:24:06 -0400 -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 9229caf16997e8bd6da6fae1532372827ec80291..8570b0ecd2a0db9bb02ebcd12bafa1af31bf4b45 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -201,6 +201,7 @@ import net.minecraft.world.phys.Vec3; - import net.minecraft.world.phys.shapes.BooleanOp; - import net.minecraft.world.phys.shapes.Shapes; - import net.minecraft.world.phys.shapes.VoxelShape; -+import org.bukkit.NamespacedKey; - import org.slf4j.Logger; - - // CraftBukkit start -@@ -3157,21 +3158,41 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - ServerGamePacketListenerImpl.LOGGER.debug("Player {} tried to place impossible recipe {}", this.player, recipeholder.id().location()); - return; - } -+ // Paper start - Add PlayerRecipeBookClickEvent -+ NamespacedKey recipeName = org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(recipeholder.id().location()); -+ boolean makeAll = packet.useMaxItems(); -+ com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent paperEvent = new com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent( -+ this.player.getBukkitEntity(), recipeName, makeAll -+ ); -+ if (!paperEvent.callEvent()) { -+ return; -+ } -+ recipeName = paperEvent.getRecipe(); -+ makeAll = paperEvent.isMakeAll(); -+ if (org.bukkit.event.player.PlayerRecipeBookClickEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ // Paper end - Add PlayerRecipeBookClickEvent - - // CraftBukkit start - implement PlayerRecipeBookClickEvent -- org.bukkit.inventory.Recipe recipe = recipeholder.toBukkitRecipe(); -+ org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(recipeName); // Paper - Add PlayerRecipeBookClickEvent - forward to legacy event - if (recipe == null) { - return; - } -- org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, packet.useMaxItems()); -+ // Paper start - Add PlayerRecipeBookClickEvent - forward to legacy event -+ org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, makeAll); -+ recipeName = ((org.bukkit.Keyed) event.getRecipe()).getKey(); -+ makeAll = event.isShiftClick(); -+ } -+ if (!(this.player.containerMenu instanceof RecipeBookMenu)) { -+ return; -+ } -+ // Paper end - Add PlayerRecipeBookClickEvent - forward to legacy event - - // Cast to keyed should be safe as the recipe will never be a MerchantRecipe. -- recipeholder = this.server.getRecipeManager().byKey(CraftRecipe.toMinecraft(((org.bukkit.Keyed) event.getRecipe()).getKey())).orElse(null); -+ recipeholder = this.server.getRecipeManager().byKey(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.RECIPE, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(recipeName))).orElse(null); // Paper - Add PlayerRecipeBookClickEvent - forward to legacy event - if (recipeholder == null) { - return; - } -- -- RecipeBookMenu.PostPlaceAction containerrecipebook_a = containerrecipebook.handlePlacement(event.isShiftClick(), this.player.isCreative(), recipeholder, this.player.serverLevel(), this.player.getInventory()); -+ RecipeBookMenu.PostPlaceAction containerrecipebook_a = containerrecipebook.handlePlacement(makeAll, this.player.isCreative(), recipeholder, this.player.serverLevel(), this.player.getInventory()); - // CraftBukkit end - - if (containerrecipebook_a == RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE) { diff --git a/patches/server/0364-Hide-sync-chunk-writes-behind-flag.patch b/patches/server/0364-Hide-sync-chunk-writes-behind-flag.patch new file mode 100644 index 0000000000..8703d3b68a --- /dev/null +++ b/patches/server/0364-Hide-sync-chunk-writes-behind-flag.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Fri, 26 Jun 2020 22:35:08 -0700 +Subject: [PATCH] Hide sync chunk writes behind flag + +Syncing writes on each write call has terrible performance +on harddrives. + +-DPaper.enable-sync-chunk-writes=true to enable + +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java +index 83d279a66484dfeef3ce34bef3d1c8f221c67f6d..a2633780619d73c29a23cb8b6a208ca9ba549fb0 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java +@@ -146,7 +146,7 @@ public class DedicatedServerProperties extends Settings { + return Mth.clamp(integer, 1, 29999984); + }, 29999984); +- this.syncChunkWrites = this.get("sync-chunk-writes", true); ++ this.syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - Hide sync chunk writes behind flag + this.regionFileComression = this.get("region-file-compression", "deflate"); + this.enableJmxMonitoring = this.get("enable-jmx-monitoring", false); + this.enableStatus = this.get("enable-status", true); diff --git a/patches/server/0365-Add-permission-for-command-blocks.patch b/patches/server/0365-Add-permission-for-command-blocks.patch new file mode 100644 index 0000000000..3d1a2ff8ed --- /dev/null +++ b/patches/server/0365-Add-permission-for-command-blocks.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 16 May 2020 10:05:30 +0200 +Subject: [PATCH] Add permission for command blocks + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 4623c8acd125dff4919c4e2045b848310d785da5..86e4559da2344f228ef4d1c4ac3c115fa0266d23 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -403,7 +403,7 @@ public class ServerPlayerGameMode { + BlockEntity tileentity = this.level.getBlockEntity(pos); + Block block = iblockdata.getBlock(); + +- if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) { ++ if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks() && !(block instanceof net.minecraft.world.level.block.CommandBlock && (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission + this.level.sendBlockUpdated(pos, iblockdata, iblockdata, 3); + 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 8570b0ecd2a0db9bb02ebcd12bafa1af31bf4b45..e3b238691a57e4d8317e84921f4c2e67ca994006 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -816,7 +816,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (!this.server.isCommandBlockEnabled()) { + this.player.sendSystemMessage(Component.translatable("advMode.notEnabled")); +- } else if (!this.player.canUseGameMasterBlocks()) { ++ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission + this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); + } else { + BaseCommandBlock commandblocklistenerabstract = null; +@@ -883,7 +883,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (!this.server.isCommandBlockEnabled()) { + this.player.sendSystemMessage(Component.translatable("advMode.notEnabled")); +- } else if (!this.player.canUseGameMasterBlocks()) { ++ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission + this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); + } else { + BaseCommandBlock commandblocklistenerabstract = packet.getCommandBlock(this.player.level()); +diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java +index 0898dfd42de0c25938d9a25c18f43d5b1a16aa6c..a0e59b236dff1f861a0e987764a77ee203504412 100644 +--- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java ++++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java +@@ -204,7 +204,7 @@ public abstract class BaseCommandBlock implements CommandSource { + } + + public InteractionResult usedBy(Player player) { +- if (!player.canUseGameMasterBlocks()) { ++ if (!player.canUseGameMasterBlocks() && (!player.isCreative() || !player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission + return InteractionResult.PASS; + } else { + if (player.getCommandSenderWorld().isClientSide) { +diff --git a/src/main/java/net/minecraft/world/level/block/CommandBlock.java b/src/main/java/net/minecraft/world/level/block/CommandBlock.java +index 090846f3b310959b3a7d16ed341f8d2100938c9d..40c79df819a111b88adbbd006e3696f3684090c9 100644 +--- a/src/main/java/net/minecraft/world/level/block/CommandBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/CommandBlock.java +@@ -152,7 +152,7 @@ public class CommandBlock extends BaseEntityBlock implements GameMasterBlock { + protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { + BlockEntity tileentity = world.getBlockEntity(pos); + +- if (tileentity instanceof CommandBlockEntity && player.canUseGameMasterBlocks()) { ++ if (tileentity instanceof CommandBlockEntity && (player.canUseGameMasterBlocks() || (player.isCreative() && player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission + player.openCommandBlock((CommandBlockEntity) tileentity); + return InteractionResult.SUCCESS; + } else { +diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java +index 245ad120a36b6defca7e6889faae1ca5fc33d0c7..e0e61115ada9a49d4c528c5d4e02a1ca571d9531 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java +@@ -16,6 +16,7 @@ public final class CraftDefaultPermissions { + DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".nbt.copy", "Gives the user the ability to copy NBT in creative", org.bukkit.permissions.PermissionDefault.TRUE, parent); + DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick", "Gives the user the ability to use the debug stick in creative", org.bukkit.permissions.PermissionDefault.OP, parent); + DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick.always", "Gives the user the ability to use the debug stick in all game modes", org.bukkit.permissions.PermissionDefault.FALSE/* , parent */); // Paper - should not have this parent, as it's not a "vanilla" utility ++ DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".commandblock", "Gives the user the ability to use command blocks.", org.bukkit.permissions.PermissionDefault.OP, parent); // Paper + // Spigot end + parent.recalculatePermissibles(); + } diff --git a/patches/server/0365-Hide-sync-chunk-writes-behind-flag.patch b/patches/server/0365-Hide-sync-chunk-writes-behind-flag.patch deleted file mode 100644 index 8703d3b68a..0000000000 --- a/patches/server/0365-Hide-sync-chunk-writes-behind-flag.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Fri, 26 Jun 2020 22:35:08 -0700 -Subject: [PATCH] Hide sync chunk writes behind flag - -Syncing writes on each write call has terrible performance -on harddrives. - --DPaper.enable-sync-chunk-writes=true to enable - -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java -index 83d279a66484dfeef3ce34bef3d1c8f221c67f6d..a2633780619d73c29a23cb8b6a208ca9ba549fb0 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java -@@ -146,7 +146,7 @@ public class DedicatedServerProperties extends Settings { - return Mth.clamp(integer, 1, 29999984); - }, 29999984); -- this.syncChunkWrites = this.get("sync-chunk-writes", true); -+ this.syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - Hide sync chunk writes behind flag - this.regionFileComression = this.get("region-file-compression", "deflate"); - this.enableJmxMonitoring = this.get("enable-jmx-monitoring", false); - this.enableStatus = this.get("enable-status", true); diff --git a/patches/server/0366-Add-permission-for-command-blocks.patch b/patches/server/0366-Add-permission-for-command-blocks.patch deleted file mode 100644 index 3d1a2ff8ed..0000000000 --- a/patches/server/0366-Add-permission-for-command-blocks.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 16 May 2020 10:05:30 +0200 -Subject: [PATCH] Add permission for command blocks - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 4623c8acd125dff4919c4e2045b848310d785da5..86e4559da2344f228ef4d1c4ac3c115fa0266d23 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -403,7 +403,7 @@ public class ServerPlayerGameMode { - BlockEntity tileentity = this.level.getBlockEntity(pos); - Block block = iblockdata.getBlock(); - -- if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) { -+ if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks() && !(block instanceof net.minecraft.world.level.block.CommandBlock && (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission - this.level.sendBlockUpdated(pos, iblockdata, iblockdata, 3); - 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 8570b0ecd2a0db9bb02ebcd12bafa1af31bf4b45..e3b238691a57e4d8317e84921f4c2e67ca994006 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -816,7 +816,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); - if (!this.server.isCommandBlockEnabled()) { - this.player.sendSystemMessage(Component.translatable("advMode.notEnabled")); -- } else if (!this.player.canUseGameMasterBlocks()) { -+ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission - this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); - } else { - BaseCommandBlock commandblocklistenerabstract = null; -@@ -883,7 +883,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); - if (!this.server.isCommandBlockEnabled()) { - this.player.sendSystemMessage(Component.translatable("advMode.notEnabled")); -- } else if (!this.player.canUseGameMasterBlocks()) { -+ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission - this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); - } else { - BaseCommandBlock commandblocklistenerabstract = packet.getCommandBlock(this.player.level()); -diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -index 0898dfd42de0c25938d9a25c18f43d5b1a16aa6c..a0e59b236dff1f861a0e987764a77ee203504412 100644 ---- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -@@ -204,7 +204,7 @@ public abstract class BaseCommandBlock implements CommandSource { - } - - public InteractionResult usedBy(Player player) { -- if (!player.canUseGameMasterBlocks()) { -+ if (!player.canUseGameMasterBlocks() && (!player.isCreative() || !player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission - return InteractionResult.PASS; - } else { - if (player.getCommandSenderWorld().isClientSide) { -diff --git a/src/main/java/net/minecraft/world/level/block/CommandBlock.java b/src/main/java/net/minecraft/world/level/block/CommandBlock.java -index 090846f3b310959b3a7d16ed341f8d2100938c9d..40c79df819a111b88adbbd006e3696f3684090c9 100644 ---- a/src/main/java/net/minecraft/world/level/block/CommandBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CommandBlock.java -@@ -152,7 +152,7 @@ public class CommandBlock extends BaseEntityBlock implements GameMasterBlock { - protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { - BlockEntity tileentity = world.getBlockEntity(pos); - -- if (tileentity instanceof CommandBlockEntity && player.canUseGameMasterBlocks()) { -+ if (tileentity instanceof CommandBlockEntity && (player.canUseGameMasterBlocks() || (player.isCreative() && player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission - player.openCommandBlock((CommandBlockEntity) tileentity); - return InteractionResult.SUCCESS; - } else { -diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java -index 245ad120a36b6defca7e6889faae1ca5fc33d0c7..e0e61115ada9a49d4c528c5d4e02a1ca571d9531 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java -@@ -16,6 +16,7 @@ public final class CraftDefaultPermissions { - DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".nbt.copy", "Gives the user the ability to copy NBT in creative", org.bukkit.permissions.PermissionDefault.TRUE, parent); - DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick", "Gives the user the ability to use the debug stick in creative", org.bukkit.permissions.PermissionDefault.OP, parent); - DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick.always", "Gives the user the ability to use the debug stick in all game modes", org.bukkit.permissions.PermissionDefault.FALSE/* , parent */); // Paper - should not have this parent, as it's not a "vanilla" utility -+ DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".commandblock", "Gives the user the ability to use command blocks.", org.bukkit.permissions.PermissionDefault.OP, parent); // Paper - // Spigot end - parent.recalculatePermissibles(); - } diff --git a/patches/server/0366-Ensure-Entity-position-and-AABB-are-never-invalid.patch b/patches/server/0366-Ensure-Entity-position-and-AABB-are-never-invalid.patch new file mode 100644 index 0000000000..2190689071 --- /dev/null +++ b/patches/server/0366-Ensure-Entity-position-and-AABB-are-never-invalid.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 10 May 2020 22:12:46 -0400 +Subject: [PATCH] Ensure Entity position and AABB are never invalid + +Co-authored-by: Spottedleaf + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 2dc87373d687c04f89c7a3b033c8a188ba415904..abcdb8d082dd0bbcd60c1d0d924b6774dd196ea7 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -678,8 +678,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public void setPos(double x, double y, double z) { +- this.setPosRaw(x, y, z); +- this.setBoundingBox(this.makeBoundingBox()); ++ this.setPosRaw(x, y, z, true); // Paper - Block invalid positions and bounding box; force update ++ // this.setBoundingBox(this.makeBoundingBox()); // Paper - Block invalid positions and bounding box; move into setPosRaw + } + + protected final AABB makeBoundingBox() { +@@ -4468,7 +4468,29 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return this.getZ((2.0D * this.random.nextDouble() - 1.0D) * widthScale); + } + ++ // Paper start - Block invalid positions and bounding box ++ public static boolean checkPosition(Entity entity, double newX, double newY, double newZ) { ++ if (Double.isFinite(newX) && Double.isFinite(newY) && Double.isFinite(newZ)) { ++ return true; ++ } ++ ++ String entityInfo; ++ try { ++ entityInfo = entity.toString(); ++ } catch (Exception ex) { ++ entityInfo = "[Entity info unavailable] "; ++ } ++ LOGGER.error("New entity position is invalid! Tried to set invalid position ({},{},{}) for entity {} located at {}, entity info: {}", newX, newY, newZ, entity.getClass().getName(), entity.position, entityInfo, new Throwable()); ++ return false; ++ } + public final void setPosRaw(double x, double y, double z) { ++ this.setPosRaw(x, y, z, false); ++ } ++ public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) { ++ if (!checkPosition(this, x, y, z)) { ++ return; ++ } ++ // Paper end - Block invalid positions and bounding box + if (this.position.x != x || this.position.y != y || this.position.z != z) { + this.position = new Vec3(x, y, z); + int i = Mth.floor(x); +@@ -4486,6 +4508,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.levelCallback.onMove(); + } + ++ // Paper start - Block invalid positions and bounding box; don't allow desync of pos and AABB ++ // hanging has its own special logic ++ if (!(this instanceof net.minecraft.world.entity.decoration.HangingEntity) && (forceBoundingBoxUpdate || this.position.x != x || this.position.y != y || this.position.z != z)) { ++ this.setBoundingBox(this.makeBoundingBox()); ++ } ++ // Paper end - Block invalid positions and bounding box + } + + public void checkDespawn() {} diff --git a/patches/server/0367-Ensure-Entity-position-and-AABB-are-never-invalid.patch b/patches/server/0367-Ensure-Entity-position-and-AABB-are-never-invalid.patch deleted file mode 100644 index 19958b8498..0000000000 --- a/patches/server/0367-Ensure-Entity-position-and-AABB-are-never-invalid.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 10 May 2020 22:12:46 -0400 -Subject: [PATCH] Ensure Entity position and AABB are never invalid - -Co-authored-by: Spottedleaf - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index c48f634fe80919cb1c2c4d2c1fd647dc63c87749..3860265a50b62fbd36c9e1b32680c3b62d5342a6 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -678,8 +678,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public void setPos(double x, double y, double z) { -- this.setPosRaw(x, y, z); -- this.setBoundingBox(this.makeBoundingBox()); -+ this.setPosRaw(x, y, z, true); // Paper - Block invalid positions and bounding box; force update -+ // this.setBoundingBox(this.makeBoundingBox()); // Paper - Block invalid positions and bounding box; move into setPosRaw - } - - protected final AABB makeBoundingBox() { -@@ -4468,7 +4468,29 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return this.getZ((2.0D * this.random.nextDouble() - 1.0D) * widthScale); - } - -+ // Paper start - Block invalid positions and bounding box -+ public static boolean checkPosition(Entity entity, double newX, double newY, double newZ) { -+ if (Double.isFinite(newX) && Double.isFinite(newY) && Double.isFinite(newZ)) { -+ return true; -+ } -+ -+ String entityInfo; -+ try { -+ entityInfo = entity.toString(); -+ } catch (Exception ex) { -+ entityInfo = "[Entity info unavailable] "; -+ } -+ LOGGER.error("New entity position is invalid! Tried to set invalid position ({},{},{}) for entity {} located at {}, entity info: {}", newX, newY, newZ, entity.getClass().getName(), entity.position, entityInfo, new Throwable()); -+ return false; -+ } - public final void setPosRaw(double x, double y, double z) { -+ this.setPosRaw(x, y, z, false); -+ } -+ public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) { -+ if (!checkPosition(this, x, y, z)) { -+ return; -+ } -+ // Paper end - Block invalid positions and bounding box - if (this.position.x != x || this.position.y != y || this.position.z != z) { - this.position = new Vec3(x, y, z); - int i = Mth.floor(x); -@@ -4486,6 +4508,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.levelCallback.onMove(); - } - -+ // Paper start - Block invalid positions and bounding box; don't allow desync of pos and AABB -+ // hanging has its own special logic -+ if (!(this instanceof net.minecraft.world.entity.decoration.HangingEntity) && (forceBoundingBoxUpdate || this.position.x != x || this.position.y != y || this.position.z != z)) { -+ this.setBoundingBox(this.makeBoundingBox()); -+ } -+ // Paper end - Block invalid positions and bounding box - } - - public void checkDespawn() {} diff --git a/patches/server/0367-Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/0367-Fix-Per-World-Difficulty-Remembering-Difficulty.patch new file mode 100644 index 0000000000..6ea3956f08 --- /dev/null +++ b/patches/server/0367-Fix-Per-World-Difficulty-Remembering-Difficulty.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 28 Jun 2020 03:59:10 -0400 +Subject: [PATCH] Fix Per World Difficulty / Remembering Difficulty + +Fixes per world difficulty with /difficulty command and also +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 84999223df47a9eccbcec4e1ea80786090d8d9c5..83848e30eeff52ccad591deb0d9e3a8ba1a122ed 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -850,7 +850,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { + return Component.translatable("commands.difficulty.success", difficulty.getDisplayName()); + }, true); +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index fe1975675189c6d1a63c42b7959fa40b5ac95ef8..9a3e73a5c206b78dfcf6f41a47b614342e52acc8 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -337,7 +337,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + + @Override + public void forceDifficulty() { +- this.setDifficulty(this.getProperties().difficulty, true); ++ // this.setDifficulty(this.getProperties().difficulty, true); // Paper - per level difficulty; Don't overwrite level.dat's difficulty, keep current + } + + @Override +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index e3b238691a57e4d8317e84921f4c2e67ca994006..bc0380322ea9acd055ce844f23c6e38815e31831 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -3366,7 +3366,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (this.player.hasPermissions(2) || this.isSingleplayerOwner()) { +- this.server.setDifficulty(packet.getDifficulty(), false); ++ // this.server.setDifficulty(packet.getDifficulty(), false); // Paper - per level difficulty; don't allow clients to change this + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index ca8eb3216c4331a95ab44f923f6b49641662505f..9905555f249db72649bde8401835dd816ed7b428 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1000,8 +1000,8 @@ public final class CraftServer implements Server { + org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot + this.console.paperConfigurations.reloadConfigs(this.console); + for (ServerLevel world : this.console.getAllLevels()) { +- world.serverLevelData.setDifficulty(config.difficulty); +- world.setSpawnSettings(config.spawnMonsters); ++ // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty ++ world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) + + for (SpawnCategory spawnCategory : SpawnCategory.values()) { + if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index c310a8bae84af6c20f7d976fb7cd683885407cc8..031c46e8cf1c49c4db2887dc32cbad75532f8faa 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1170,7 +1170,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setDifficulty(Difficulty difficulty) { +- this.getHandle().serverLevelData.setDifficulty(net.minecraft.world.Difficulty.byId(difficulty.getValue())); ++ this.getHandle().getServer().setDifficulty(this.getHandle(), net.minecraft.world.Difficulty.byId(difficulty.getValue()), true); // Paper - per level difficulty; don't skip other difficulty-changing logic + } + + @Override diff --git a/patches/server/0368-Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/0368-Fix-Per-World-Difficulty-Remembering-Difficulty.patch deleted file mode 100644 index 6ea3956f08..0000000000 --- a/patches/server/0368-Fix-Per-World-Difficulty-Remembering-Difficulty.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 28 Jun 2020 03:59:10 -0400 -Subject: [PATCH] Fix Per World Difficulty / Remembering Difficulty - -Fixes per world difficulty with /difficulty command and also -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 84999223df47a9eccbcec4e1ea80786090d8d9c5..83848e30eeff52ccad591deb0d9e3a8ba1a122ed 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -850,7 +850,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { - return Component.translatable("commands.difficulty.success", difficulty.getDisplayName()); - }, true); -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index fe1975675189c6d1a63c42b7959fa40b5ac95ef8..9a3e73a5c206b78dfcf6f41a47b614342e52acc8 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -337,7 +337,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - - @Override - public void forceDifficulty() { -- this.setDifficulty(this.getProperties().difficulty, true); -+ // this.setDifficulty(this.getProperties().difficulty, true); // Paper - per level difficulty; Don't overwrite level.dat's difficulty, keep current - } - - @Override -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index e3b238691a57e4d8317e84921f4c2e67ca994006..bc0380322ea9acd055ce844f23c6e38815e31831 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3366,7 +3366,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) { - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); - if (this.player.hasPermissions(2) || this.isSingleplayerOwner()) { -- this.server.setDifficulty(packet.getDifficulty(), false); -+ // this.server.setDifficulty(packet.getDifficulty(), false); // Paper - per level difficulty; don't allow clients to change this - } - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index ca8eb3216c4331a95ab44f923f6b49641662505f..9905555f249db72649bde8401835dd816ed7b428 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1000,8 +1000,8 @@ public final class CraftServer implements Server { - org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot - this.console.paperConfigurations.reloadConfigs(this.console); - for (ServerLevel world : this.console.getAllLevels()) { -- world.serverLevelData.setDifficulty(config.difficulty); -- world.setSpawnSettings(config.spawnMonsters); -+ // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty -+ world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) - - for (SpawnCategory spawnCategory : SpawnCategory.values()) { - if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index c310a8bae84af6c20f7d976fb7cd683885407cc8..031c46e8cf1c49c4db2887dc32cbad75532f8faa 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1170,7 +1170,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setDifficulty(Difficulty difficulty) { -- this.getHandle().serverLevelData.setDifficulty(net.minecraft.world.Difficulty.byId(difficulty.getValue())); -+ this.getHandle().getServer().setDifficulty(this.getHandle(), net.minecraft.world.Difficulty.byId(difficulty.getValue()), true); // Paper - per level difficulty; don't skip other difficulty-changing logic - } - - @Override diff --git a/patches/server/0368-Paper-dumpitem-command.patch b/patches/server/0368-Paper-dumpitem-command.patch new file mode 100644 index 0000000000..3c84400215 --- /dev/null +++ b/patches/server/0368-Paper-dumpitem-command.patch @@ -0,0 +1,158 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 28 Jun 2020 19:27:20 -0400 +Subject: [PATCH] Paper dumpitem command + +Let's you quickly view the item in your hands NBT data + +diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java +index 3010d57efcc97fb409bfe43b1fc9af198c099a67..cdad0fd5257ae842f83b9c1c98b4565b468d4f54 100644 +--- a/src/main/java/io/papermc/paper/command/PaperCommand.java ++++ b/src/main/java/io/papermc/paper/command/PaperCommand.java +@@ -39,6 +39,7 @@ public final class PaperCommand extends Command { + commands.put(Set.of("version"), new VersionCommand()); + commands.put(Set.of("dumpplugins"), new DumpPluginsCommand()); + commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); ++ commands.put(Set.of("dumpitem"), new DumpItemCommand()); + + 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/DumpItemCommand.java b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b4b90c1bda72f845756b46e2316d952361989697 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java +@@ -0,0 +1,133 @@ ++package io.papermc.paper.command.subcommands; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.command.CommandUtil; ++import io.papermc.paper.command.PaperSubcommand; ++import java.util.ArrayList; ++import java.util.Collections; ++import java.util.IdentityHashMap; ++import java.util.List; ++import java.util.Map; ++import java.util.Optional; ++import java.util.Set; ++import java.util.function.Consumer; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.ComponentLike; ++import net.kyori.adventure.text.JoinConfiguration; ++import net.kyori.adventure.text.TextComponent; ++import net.minecraft.core.Registry; ++import net.minecraft.core.RegistryAccess; ++import net.minecraft.core.component.DataComponentMap; ++import net.minecraft.core.component.DataComponentPatch; ++import net.minecraft.core.component.DataComponentType; ++import net.minecraft.core.component.TypedDataComponent; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.nbt.NbtOps; ++import net.minecraft.nbt.NbtUtils; ++import net.minecraft.nbt.SnbtPrinterTagVisitor; ++import net.minecraft.nbt.Tag; ++import net.minecraft.resources.RegistryOps; ++import net.minecraft.world.item.ItemStack; ++import org.bukkit.command.CommandSender; ++import org.bukkit.craftbukkit.CraftServer; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.entity.Player; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++import static net.kyori.adventure.text.Component.join; ++import static net.kyori.adventure.text.Component.text; ++import static net.kyori.adventure.text.Component.textOfChildren; ++import static net.kyori.adventure.text.event.ClickEvent.copyToClipboard; ++import static net.kyori.adventure.text.format.NamedTextColor.AQUA; ++import static net.kyori.adventure.text.format.NamedTextColor.GRAY; ++import static net.kyori.adventure.text.format.NamedTextColor.RED; ++import static net.kyori.adventure.text.format.NamedTextColor.WHITE; ++import static net.kyori.adventure.text.format.NamedTextColor.YELLOW; ++import static net.kyori.adventure.text.format.TextColor.color; ++import static net.kyori.adventure.text.format.TextDecoration.ITALIC; ++ ++@DefaultQualifier(NonNull.class) ++public final class DumpItemCommand implements PaperSubcommand { ++ @Override ++ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { ++ this.doDumpItem(sender, args.length > 0 && "all".equals(args[0])); ++ return true; ++ } ++ ++ @SuppressWarnings({"unchecked", "OptionalAssignedToNull", "rawtypes"}) ++ private void doDumpItem(final CommandSender sender, final boolean includeAllComponents) { ++ if (!(sender instanceof final Player player)) { ++ sender.sendMessage("Only players can use this command"); ++ return; ++ } ++ final ItemStack itemStack = CraftItemStack.asNMSCopy(player.getInventory().getItemInMainHand()); ++ final TextComponent.Builder visualOutput = Component.text(); ++ final StringBuilder itemCommandBuilder = new StringBuilder(); ++ final String itemName = itemStack.getItemHolder().unwrapKey().orElseThrow().location().toString(); ++ itemCommandBuilder.append(itemName); ++ visualOutput.append(text(itemName, YELLOW)); // item type ++ final Set> referencedComponentTypes = Collections.newSetFromMap(new IdentityHashMap<>()); ++ final DataComponentPatch patch = itemStack.getComponentsPatch(); ++ referencedComponentTypes.addAll(patch.entrySet().stream().map(Map.Entry::getKey).toList()); ++ final DataComponentMap prototype = itemStack.getItem().components(); ++ if (includeAllComponents) { ++ referencedComponentTypes.addAll(prototype.keySet()); ++ } ++ ++ final RegistryAccess.Frozen access = ((CraftServer) sender.getServer()).getServer().registryAccess(); ++ final RegistryOps ops = access.createSerializationContext(NbtOps.INSTANCE); ++ final Registry> registry = access.lookupOrThrow(Registries.DATA_COMPONENT_TYPE); ++ final List componentComponents = new ArrayList<>(); ++ final List commandComponents = new ArrayList<>(); ++ for (final DataComponentType type : referencedComponentTypes) { ++ final String path = registry.getResourceKey(type).orElseThrow().location().getPath(); ++ final @Nullable Optional patchedValue = patch.get(type); ++ final @Nullable TypedDataComponent prototypeValue = prototype.getTyped(type); ++ if (patchedValue != null) { ++ if (patchedValue.isEmpty()) { ++ componentComponents.add(text().append(text('!', RED), text(path, AQUA))); ++ commandComponents.add("!" + path); ++ } else { ++ final Tag serialized = (Tag) ((DataComponentType) type).codecOrThrow().encodeStart(ops, patchedValue.get()).getOrThrow(); ++ writeComponentValue(componentComponents::add, commandComponents::add, path, serialized); ++ } ++ } else if (includeAllComponents && prototypeValue != null) { ++ final Tag serialized = prototypeValue.encodeValue(ops).getOrThrow(); ++ writeComponentValue(componentComponents::add, commandComponents::add, path, serialized); ++ } ++ } ++ if (!componentComponents.isEmpty()) { ++ visualOutput.append( ++ text("[", color(0x8910CE)), ++ join(JoinConfiguration.separator(text(",", GRAY)), componentComponents), ++ text("]", color(0x8910CE)) ++ ); ++ itemCommandBuilder ++ .append("[") ++ .append(String.join(",", commandComponents)) ++ .append("]"); ++ } ++ player.sendMessage(visualOutput.build().compact()); ++ final Component copyMsg = text("Click to copy item definition to clipboard for use with /give", GRAY, ITALIC); ++ sender.sendMessage(copyMsg.clickEvent(copyToClipboard(itemCommandBuilder.toString()))); ++ } ++ ++ private static void writeComponentValue(final Consumer visualOutput, final Consumer commandOutput, final String path, final Tag serialized) { ++ visualOutput.accept(textOfChildren( ++ text(path, color(0xFF7FD7)), ++ text("=", WHITE), ++ PaperAdventure.asAdventure(NbtUtils.toPrettyComponent(serialized)) ++ )); ++ commandOutput.accept(path + "=" + new SnbtPrinterTagVisitor("", 0, new ArrayList<>()).visit(serialized)); ++ } ++ ++ @Override ++ public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { ++ if (args.length == 1) { ++ return CommandUtil.getListMatchingLast(sender, args, "all"); ++ } ++ return Collections.emptyList(); ++ } ++} diff --git a/patches/server/0369-Improve-Legacy-Component-serialization-size.patch b/patches/server/0369-Improve-Legacy-Component-serialization-size.patch new file mode 100644 index 0000000000..e52764c13c --- /dev/null +++ b/patches/server/0369-Improve-Legacy-Component-serialization-size.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 28 Jun 2020 19:08:41 -0400 +Subject: [PATCH] Improve Legacy Component serialization size + +Don't constantly send format: false for all formatting options when parent already +has it false + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java +index 95444fd9fecc5bda5462ca8dfeca82c5318f0895..fd697475e2df1cef8260b47dabb491beb0bd1a8e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java +@@ -48,6 +48,7 @@ public final class CraftChatMessage { + // Separate pattern with no group 3, new lines are part of previous string + private static final Pattern INCREMENTAL_PATTERN_KEEP_NEWLINES = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-orx])|((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " ]|$))))", Pattern.CASE_INSENSITIVE); + // ChatColor.b does not explicitly reset, its more of empty ++ private static final Style EMPTY = Style.EMPTY.withItalic(false); // Paper - Improve Legacy Component serialization size + private static final Style RESET = Style.EMPTY.withBold(false).withItalic(false).withUnderlined(false).withStrikethrough(false).withObfuscated(false); + + private final List list = new ArrayList(); +@@ -69,6 +70,7 @@ public final class CraftChatMessage { + Matcher matcher = (keepNewlines ? StringMessage.INCREMENTAL_PATTERN_KEEP_NEWLINES : StringMessage.INCREMENTAL_PATTERN).matcher(message); + String match = null; + boolean needsAdd = false; ++ boolean hasReset = false; // Paper - Improve Legacy Component serialization size + while (matcher.find()) { + int groupId = 0; + while ((match = matcher.group(++groupId)) == null) { +@@ -114,7 +116,26 @@ public final class CraftChatMessage { + throw new AssertionError("Unexpected message format"); + } + } else { // Color resets formatting +- this.modifier = StringMessage.RESET.withColor(format); ++ // Paper start - Improve Legacy Component serialization size ++ Style previous = modifier; ++ modifier = (!hasReset ? RESET : EMPTY).withColor(format); ++ hasReset = true; ++ if (previous.isBold()) { ++ modifier = modifier.withBold(false); ++ } ++ if (previous.isItalic()) { ++ modifier = modifier.withItalic(false); ++ } ++ if (previous.isObfuscated()) { ++ modifier = modifier.withObfuscated(false); ++ } ++ if (previous.isStrikethrough()) { ++ modifier = modifier.withStrikethrough(false); ++ } ++ if (previous.isUnderlined()) { ++ modifier = modifier.withUnderlined(false); ++ } ++ // Paper end - Improve Legacy Component serialization size + } + needsAdd = true; + break; diff --git a/patches/server/0369-Paper-dumpitem-command.patch b/patches/server/0369-Paper-dumpitem-command.patch deleted file mode 100644 index 3c84400215..0000000000 --- a/patches/server/0369-Paper-dumpitem-command.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 28 Jun 2020 19:27:20 -0400 -Subject: [PATCH] Paper dumpitem command - -Let's you quickly view the item in your hands NBT data - -diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java -index 3010d57efcc97fb409bfe43b1fc9af198c099a67..cdad0fd5257ae842f83b9c1c98b4565b468d4f54 100644 ---- a/src/main/java/io/papermc/paper/command/PaperCommand.java -+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java -@@ -39,6 +39,7 @@ public final class PaperCommand extends Command { - commands.put(Set.of("version"), new VersionCommand()); - commands.put(Set.of("dumpplugins"), new DumpPluginsCommand()); - commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); -+ commands.put(Set.of("dumpitem"), new DumpItemCommand()); - - 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/DumpItemCommand.java b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b4b90c1bda72f845756b46e2316d952361989697 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java -@@ -0,0 +1,133 @@ -+package io.papermc.paper.command.subcommands; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import io.papermc.paper.command.CommandUtil; -+import io.papermc.paper.command.PaperSubcommand; -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.IdentityHashMap; -+import java.util.List; -+import java.util.Map; -+import java.util.Optional; -+import java.util.Set; -+import java.util.function.Consumer; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.ComponentLike; -+import net.kyori.adventure.text.JoinConfiguration; -+import net.kyori.adventure.text.TextComponent; -+import net.minecraft.core.Registry; -+import net.minecraft.core.RegistryAccess; -+import net.minecraft.core.component.DataComponentMap; -+import net.minecraft.core.component.DataComponentPatch; -+import net.minecraft.core.component.DataComponentType; -+import net.minecraft.core.component.TypedDataComponent; -+import net.minecraft.core.registries.Registries; -+import net.minecraft.nbt.NbtOps; -+import net.minecraft.nbt.NbtUtils; -+import net.minecraft.nbt.SnbtPrinterTagVisitor; -+import net.minecraft.nbt.Tag; -+import net.minecraft.resources.RegistryOps; -+import net.minecraft.world.item.ItemStack; -+import org.bukkit.command.CommandSender; -+import org.bukkit.craftbukkit.CraftServer; -+import org.bukkit.craftbukkit.inventory.CraftItemStack; -+import org.bukkit.entity.Player; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; -+ -+import static net.kyori.adventure.text.Component.join; -+import static net.kyori.adventure.text.Component.text; -+import static net.kyori.adventure.text.Component.textOfChildren; -+import static net.kyori.adventure.text.event.ClickEvent.copyToClipboard; -+import static net.kyori.adventure.text.format.NamedTextColor.AQUA; -+import static net.kyori.adventure.text.format.NamedTextColor.GRAY; -+import static net.kyori.adventure.text.format.NamedTextColor.RED; -+import static net.kyori.adventure.text.format.NamedTextColor.WHITE; -+import static net.kyori.adventure.text.format.NamedTextColor.YELLOW; -+import static net.kyori.adventure.text.format.TextColor.color; -+import static net.kyori.adventure.text.format.TextDecoration.ITALIC; -+ -+@DefaultQualifier(NonNull.class) -+public final class DumpItemCommand implements PaperSubcommand { -+ @Override -+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ this.doDumpItem(sender, args.length > 0 && "all".equals(args[0])); -+ return true; -+ } -+ -+ @SuppressWarnings({"unchecked", "OptionalAssignedToNull", "rawtypes"}) -+ private void doDumpItem(final CommandSender sender, final boolean includeAllComponents) { -+ if (!(sender instanceof final Player player)) { -+ sender.sendMessage("Only players can use this command"); -+ return; -+ } -+ final ItemStack itemStack = CraftItemStack.asNMSCopy(player.getInventory().getItemInMainHand()); -+ final TextComponent.Builder visualOutput = Component.text(); -+ final StringBuilder itemCommandBuilder = new StringBuilder(); -+ final String itemName = itemStack.getItemHolder().unwrapKey().orElseThrow().location().toString(); -+ itemCommandBuilder.append(itemName); -+ visualOutput.append(text(itemName, YELLOW)); // item type -+ final Set> referencedComponentTypes = Collections.newSetFromMap(new IdentityHashMap<>()); -+ final DataComponentPatch patch = itemStack.getComponentsPatch(); -+ referencedComponentTypes.addAll(patch.entrySet().stream().map(Map.Entry::getKey).toList()); -+ final DataComponentMap prototype = itemStack.getItem().components(); -+ if (includeAllComponents) { -+ referencedComponentTypes.addAll(prototype.keySet()); -+ } -+ -+ final RegistryAccess.Frozen access = ((CraftServer) sender.getServer()).getServer().registryAccess(); -+ final RegistryOps ops = access.createSerializationContext(NbtOps.INSTANCE); -+ final Registry> registry = access.lookupOrThrow(Registries.DATA_COMPONENT_TYPE); -+ final List componentComponents = new ArrayList<>(); -+ final List commandComponents = new ArrayList<>(); -+ for (final DataComponentType type : referencedComponentTypes) { -+ final String path = registry.getResourceKey(type).orElseThrow().location().getPath(); -+ final @Nullable Optional patchedValue = patch.get(type); -+ final @Nullable TypedDataComponent prototypeValue = prototype.getTyped(type); -+ if (patchedValue != null) { -+ if (patchedValue.isEmpty()) { -+ componentComponents.add(text().append(text('!', RED), text(path, AQUA))); -+ commandComponents.add("!" + path); -+ } else { -+ final Tag serialized = (Tag) ((DataComponentType) type).codecOrThrow().encodeStart(ops, patchedValue.get()).getOrThrow(); -+ writeComponentValue(componentComponents::add, commandComponents::add, path, serialized); -+ } -+ } else if (includeAllComponents && prototypeValue != null) { -+ final Tag serialized = prototypeValue.encodeValue(ops).getOrThrow(); -+ writeComponentValue(componentComponents::add, commandComponents::add, path, serialized); -+ } -+ } -+ if (!componentComponents.isEmpty()) { -+ visualOutput.append( -+ text("[", color(0x8910CE)), -+ join(JoinConfiguration.separator(text(",", GRAY)), componentComponents), -+ text("]", color(0x8910CE)) -+ ); -+ itemCommandBuilder -+ .append("[") -+ .append(String.join(",", commandComponents)) -+ .append("]"); -+ } -+ player.sendMessage(visualOutput.build().compact()); -+ final Component copyMsg = text("Click to copy item definition to clipboard for use with /give", GRAY, ITALIC); -+ sender.sendMessage(copyMsg.clickEvent(copyToClipboard(itemCommandBuilder.toString()))); -+ } -+ -+ private static void writeComponentValue(final Consumer visualOutput, final Consumer commandOutput, final String path, final Tag serialized) { -+ visualOutput.accept(textOfChildren( -+ text(path, color(0xFF7FD7)), -+ text("=", WHITE), -+ PaperAdventure.asAdventure(NbtUtils.toPrettyComponent(serialized)) -+ )); -+ commandOutput.accept(path + "=" + new SnbtPrinterTagVisitor("", 0, new ArrayList<>()).visit(serialized)); -+ } -+ -+ @Override -+ public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { -+ if (args.length == 1) { -+ return CommandUtil.getListMatchingLast(sender, args, "all"); -+ } -+ return Collections.emptyList(); -+ } -+} diff --git a/patches/server/0370-Add-BlockStateMeta-clearBlockState.patch b/patches/server/0370-Add-BlockStateMeta-clearBlockState.patch new file mode 100644 index 0000000000..426769212c --- /dev/null +++ b/patches/server/0370-Add-BlockStateMeta-clearBlockState.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 11 Jan 2024 12:41:50 -0800 +Subject: [PATCH] Add BlockStateMeta#clearBlockState + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java +index e70b917698b381918b0b30dca7b97d36df28c897..3985e5b4e2d65faa8eaea1d4a2acc6fb1e64f959 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java +@@ -239,6 +239,13 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + return this.blockEntityTag != null; + } + ++ // Paper start - add method to clear block state ++ @Override ++ public void clearBlockState() { ++ this.blockEntityTag = null; ++ } ++ // Paper end - add method to clear block state ++ + @Override + public BlockState getBlockState() { + return (this.blockEntityTag != null) ? this.blockEntityTag.copy() : CraftMetaBlockState.getBlockState(this.material, null); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +index 3542c6e72f5ff459d50b73fa210ea835f52dfa49..c8eec04685456d89cb41466cddcc3975d0ceeb29 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +@@ -257,6 +257,13 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + this.banner = (Banner) blockState; + } + ++ // Paper start - add method to clear block state ++ @Override ++ public void clearBlockState() { ++ this.banner = null; ++ } ++ // Paper end - add method to clear block state ++ + private static Banner getBlockState(DyeColor color) { + BlockPos pos = BlockPos.ZERO; + Material stateMaterial = CraftMetaShield.shieldToBannerHack(color); diff --git a/patches/server/0370-Improve-Legacy-Component-serialization-size.patch b/patches/server/0370-Improve-Legacy-Component-serialization-size.patch deleted file mode 100644 index e52764c13c..0000000000 --- a/patches/server/0370-Improve-Legacy-Component-serialization-size.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 28 Jun 2020 19:08:41 -0400 -Subject: [PATCH] Improve Legacy Component serialization size - -Don't constantly send format: false for all formatting options when parent already -has it false - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java -index 95444fd9fecc5bda5462ca8dfeca82c5318f0895..fd697475e2df1cef8260b47dabb491beb0bd1a8e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java -@@ -48,6 +48,7 @@ public final class CraftChatMessage { - // Separate pattern with no group 3, new lines are part of previous string - private static final Pattern INCREMENTAL_PATTERN_KEEP_NEWLINES = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-orx])|((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " ]|$))))", Pattern.CASE_INSENSITIVE); - // ChatColor.b does not explicitly reset, its more of empty -+ private static final Style EMPTY = Style.EMPTY.withItalic(false); // Paper - Improve Legacy Component serialization size - private static final Style RESET = Style.EMPTY.withBold(false).withItalic(false).withUnderlined(false).withStrikethrough(false).withObfuscated(false); - - private final List list = new ArrayList(); -@@ -69,6 +70,7 @@ public final class CraftChatMessage { - Matcher matcher = (keepNewlines ? StringMessage.INCREMENTAL_PATTERN_KEEP_NEWLINES : StringMessage.INCREMENTAL_PATTERN).matcher(message); - String match = null; - boolean needsAdd = false; -+ boolean hasReset = false; // Paper - Improve Legacy Component serialization size - while (matcher.find()) { - int groupId = 0; - while ((match = matcher.group(++groupId)) == null) { -@@ -114,7 +116,26 @@ public final class CraftChatMessage { - throw new AssertionError("Unexpected message format"); - } - } else { // Color resets formatting -- this.modifier = StringMessage.RESET.withColor(format); -+ // Paper start - Improve Legacy Component serialization size -+ Style previous = modifier; -+ modifier = (!hasReset ? RESET : EMPTY).withColor(format); -+ hasReset = true; -+ if (previous.isBold()) { -+ modifier = modifier.withBold(false); -+ } -+ if (previous.isItalic()) { -+ modifier = modifier.withItalic(false); -+ } -+ if (previous.isObfuscated()) { -+ modifier = modifier.withObfuscated(false); -+ } -+ if (previous.isStrikethrough()) { -+ modifier = modifier.withStrikethrough(false); -+ } -+ if (previous.isUnderlined()) { -+ modifier = modifier.withUnderlined(false); -+ } -+ // Paper end - Improve Legacy Component serialization size - } - needsAdd = true; - break; diff --git a/patches/server/0371-Add-BlockStateMeta-clearBlockState.patch b/patches/server/0371-Add-BlockStateMeta-clearBlockState.patch deleted file mode 100644 index 426769212c..0000000000 --- a/patches/server/0371-Add-BlockStateMeta-clearBlockState.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 11 Jan 2024 12:41:50 -0800 -Subject: [PATCH] Add BlockStateMeta#clearBlockState - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -index e70b917698b381918b0b30dca7b97d36df28c897..3985e5b4e2d65faa8eaea1d4a2acc6fb1e64f959 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -@@ -239,6 +239,13 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - return this.blockEntityTag != null; - } - -+ // Paper start - add method to clear block state -+ @Override -+ public void clearBlockState() { -+ this.blockEntityTag = null; -+ } -+ // Paper end - add method to clear block state -+ - @Override - public BlockState getBlockState() { - return (this.blockEntityTag != null) ? this.blockEntityTag.copy() : CraftMetaBlockState.getBlockState(this.material, null); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -index 3542c6e72f5ff459d50b73fa210ea835f52dfa49..c8eec04685456d89cb41466cddcc3975d0ceeb29 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -@@ -257,6 +257,13 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - this.banner = (Banner) blockState; - } - -+ // Paper start - add method to clear block state -+ @Override -+ public void clearBlockState() { -+ this.banner = null; -+ } -+ // Paper end - add method to clear block state -+ - private static Banner getBlockState(DyeColor color) { - BlockPos pos = BlockPos.ZERO; - Material stateMaterial = CraftMetaShield.shieldToBannerHack(color); diff --git a/patches/server/0371-Convert-legacy-attributes-in-Item-Meta.patch b/patches/server/0371-Convert-legacy-attributes-in-Item-Meta.patch new file mode 100644 index 0000000000..bfbf591996 --- /dev/null +++ b/patches/server/0371-Convert-legacy-attributes-in-Item-Meta.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 1 Jul 2020 04:50:22 -0400 +Subject: [PATCH] Convert legacy attributes in Item Meta + + +diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java +index de40e522960469b98f987bd688489740446d9f85..5678d2007d5adf45dec0638c5dd848b601801814 100644 +--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java +@@ -9,6 +9,20 @@ import org.bukkit.attribute.AttributeInstance; + public class CraftAttributeMap implements Attributable { + + private final AttributeMap handle; ++ // Paper start - convert legacy attributes ++ private static final com.google.common.collect.ImmutableMap legacyNMS = com.google.common.collect.ImmutableMap.builder().put("generic.maxHealth", "generic.max_health").put("Max Health", "generic.max_health").put("zombie.spawnReinforcements", "zombie.spawn_reinforcements").put("Spawn Reinforcements Chance", "zombie.spawn_reinforcements").put("horse.jumpStrength", "horse.jump_strength").put("Jump Strength", "horse.jump_strength").put("generic.followRange", "generic.follow_range").put("Follow Range", "generic.follow_range").put("generic.knockbackResistance", "generic.knockback_resistance").put("Knockback Resistance", "generic.knockback_resistance").put("generic.movementSpeed", "generic.movement_speed").put("Movement Speed", "generic.movement_speed").put("generic.flyingSpeed", "generic.flying_speed").put("Flying Speed", "generic.flying_speed").put("generic.attackDamage", "generic.attack_damage").put("generic.attackKnockback", "generic.attack_knockback").put("generic.attackSpeed", "generic.attack_speed").put("generic.armorToughness", "generic.armor_toughness").build(); ++ ++ public static String convertIfNeeded(String nms) { ++ if (nms == null) { ++ return null; ++ } ++ nms = legacyNMS.getOrDefault(nms, nms); ++ if (!nms.toLowerCase(java.util.Locale.ROOT).equals(nms) || nms.indexOf(' ') != -1) { ++ return null; ++ } ++ return nms; ++ } ++ // Paper end + + public CraftAttributeMap(AttributeMap handle) { + this.handle = handle; +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index 3c44f5509e63dd673f0b8e701720984b78b9b7c4..fba042d6934f7e871114c81f97a6ac88a9b59212 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -816,7 +816,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + AttributeModifier attribMod = CraftAttributeInstance.convert(nmsModifier); + +- String attributeName = entry.getString(CraftMetaItem.ATTRIBUTES_IDENTIFIER.NBT); ++ String attributeName = org.bukkit.craftbukkit.attribute.CraftAttributeMap.convertIfNeeded(entry.getString(CraftMetaItem.ATTRIBUTES_IDENTIFIER.NBT)); // Paper + if (attributeName == null || attributeName.isEmpty()) { + continue; + } diff --git a/patches/server/0372-Convert-legacy-attributes-in-Item-Meta.patch b/patches/server/0372-Convert-legacy-attributes-in-Item-Meta.patch deleted file mode 100644 index bfbf591996..0000000000 --- a/patches/server/0372-Convert-legacy-attributes-in-Item-Meta.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 1 Jul 2020 04:50:22 -0400 -Subject: [PATCH] Convert legacy attributes in Item Meta - - -diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java -index de40e522960469b98f987bd688489740446d9f85..5678d2007d5adf45dec0638c5dd848b601801814 100644 ---- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java -@@ -9,6 +9,20 @@ import org.bukkit.attribute.AttributeInstance; - public class CraftAttributeMap implements Attributable { - - private final AttributeMap handle; -+ // Paper start - convert legacy attributes -+ private static final com.google.common.collect.ImmutableMap legacyNMS = com.google.common.collect.ImmutableMap.builder().put("generic.maxHealth", "generic.max_health").put("Max Health", "generic.max_health").put("zombie.spawnReinforcements", "zombie.spawn_reinforcements").put("Spawn Reinforcements Chance", "zombie.spawn_reinforcements").put("horse.jumpStrength", "horse.jump_strength").put("Jump Strength", "horse.jump_strength").put("generic.followRange", "generic.follow_range").put("Follow Range", "generic.follow_range").put("generic.knockbackResistance", "generic.knockback_resistance").put("Knockback Resistance", "generic.knockback_resistance").put("generic.movementSpeed", "generic.movement_speed").put("Movement Speed", "generic.movement_speed").put("generic.flyingSpeed", "generic.flying_speed").put("Flying Speed", "generic.flying_speed").put("generic.attackDamage", "generic.attack_damage").put("generic.attackKnockback", "generic.attack_knockback").put("generic.attackSpeed", "generic.attack_speed").put("generic.armorToughness", "generic.armor_toughness").build(); -+ -+ public static String convertIfNeeded(String nms) { -+ if (nms == null) { -+ return null; -+ } -+ nms = legacyNMS.getOrDefault(nms, nms); -+ if (!nms.toLowerCase(java.util.Locale.ROOT).equals(nms) || nms.indexOf(' ') != -1) { -+ return null; -+ } -+ return nms; -+ } -+ // Paper end - - public CraftAttributeMap(AttributeMap handle) { - this.handle = handle; -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index 3c44f5509e63dd673f0b8e701720984b78b9b7c4..fba042d6934f7e871114c81f97a6ac88a9b59212 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -816,7 +816,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - AttributeModifier attribMod = CraftAttributeInstance.convert(nmsModifier); - -- String attributeName = entry.getString(CraftMetaItem.ATTRIBUTES_IDENTIFIER.NBT); -+ String attributeName = org.bukkit.craftbukkit.attribute.CraftAttributeMap.convertIfNeeded(entry.getString(CraftMetaItem.ATTRIBUTES_IDENTIFIER.NBT)); // Paper - if (attributeName == null || attributeName.isEmpty()) { - continue; - } diff --git a/patches/server/0372-Do-not-accept-invalid-client-settings.patch b/patches/server/0372-Do-not-accept-invalid-client-settings.patch new file mode 100644 index 0000000000..61d7b987d0 --- /dev/null +++ b/patches/server/0372-Do-not-accept-invalid-client-settings.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sat, 7 May 2022 14:58:53 -0700 +Subject: [PATCH] Do not accept invalid client settings + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index bc0380322ea9acd055ce844f23c6e38815e31831..eab19d5ac362c4779e91fad0ede3e4c26f29ab01 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -3352,6 +3352,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + @Override + public void handleClientInformation(ServerboundClientInformationPacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); ++ // Paper start - do not accept invalid information ++ if (packet.information().viewDistance() < 0) { ++ LOGGER.warn("Disconnecting " + this.player.getScoreboardName() + " for invalid view distance: " + packet.information().viewDistance()); ++ this.disconnect(Component.literal("Invalid client settings"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); ++ return; ++ } ++ // Paper end - do not accept invalid information + boolean flag = this.player.isModelPartShown(PlayerModelPart.HAT); + + this.player.updateOptions(packet.information()); diff --git a/patches/server/0373-Do-not-accept-invalid-client-settings.patch b/patches/server/0373-Do-not-accept-invalid-client-settings.patch deleted file mode 100644 index 61d7b987d0..0000000000 --- a/patches/server/0373-Do-not-accept-invalid-client-settings.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 7 May 2022 14:58:53 -0700 -Subject: [PATCH] Do not accept invalid client settings - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index bc0380322ea9acd055ce844f23c6e38815e31831..eab19d5ac362c4779e91fad0ede3e4c26f29ab01 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3352,6 +3352,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - @Override - public void handleClientInformation(ServerboundClientInformationPacket packet) { - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); -+ // Paper start - do not accept invalid information -+ if (packet.information().viewDistance() < 0) { -+ LOGGER.warn("Disconnecting " + this.player.getScoreboardName() + " for invalid view distance: " + packet.information().viewDistance()); -+ this.disconnect(Component.literal("Invalid client settings"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); -+ return; -+ } -+ // Paper end - do not accept invalid information - boolean flag = this.player.isModelPartShown(PlayerModelPart.HAT); - - this.player.updateOptions(packet.information()); diff --git a/patches/server/0373-Improve-fix-EntityTargetLivingEntityEvent.patch b/patches/server/0373-Improve-fix-EntityTargetLivingEntityEvent.patch new file mode 100644 index 0000000000..2777b41e11 --- /dev/null +++ b/patches/server/0373-Improve-fix-EntityTargetLivingEntityEvent.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 9 Dec 2022 03:10:23 -0800 +Subject: [PATCH] Improve/fix EntityTargetLivingEntityEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java +index 70df68169b17fa5f732e4c73a86376ba6eb9ca13..b31f6ccc95132a7dd022b454d28814b684d99d4c 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java +@@ -46,9 +46,22 @@ public class StopAttackingIfTargetInvalid { + if (entityinsentient.canAttack(entityliving) && (!shouldForgetIfTargetUnreachable || !StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) && entityliving.isAlive() && entityliving.level() == entityinsentient.level() && !condition.test(worldserver, entityliving)) { + return true; + } else { ++ // Paper start - better track target change reason ++ final EntityTargetEvent.TargetReason reason; ++ if (!entityinsentient.canAttack(entityliving)) { ++ reason = EntityTargetEvent.TargetReason.TARGET_INVALID; ++ } else if (shouldForgetIfTargetUnreachable && StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) { ++ reason = EntityTargetEvent.TargetReason.FORGOT_TARGET; ++ } else if (!entityliving.isAlive()) { ++ reason = EntityTargetEvent.TargetReason.TARGET_DIED; ++ } else if (entityliving.level() != entityinsentient.level()) { ++ reason = EntityTargetEvent.TargetReason.TARGET_OTHER_LEVEL; ++ } else { ++ reason = EntityTargetEvent.TargetReason.TARGET_INVALID; ++ } ++ // Paper end + // CraftBukkit start +- LivingEntity old = entityinsentient.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null); +- EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, null, (old != null && !old.isAlive()) ? EntityTargetEvent.TargetReason.TARGET_DIED : EntityTargetEvent.TargetReason.FORGOT_TARGET); ++ EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, null, reason); // Paper + if (event.isCancelled()) { + return false; + } diff --git a/patches/server/0374-Add-entity-liquid-API.patch b/patches/server/0374-Add-entity-liquid-API.patch new file mode 100644 index 0000000000..e7b8d36eb5 --- /dev/null +++ b/patches/server/0374-Add-entity-liquid-API.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 2 Jul 2020 18:11:43 -0500 +Subject: [PATCH] Add entity liquid API + +== AT == +public net.minecraft.world.entity.Entity isInRain()Z +public net.minecraft.world.entity.Entity isInBubbleColumn()Z + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 73788d702a0a814fe7b1e64b33a3b97ca1777662..ec122fa4e443290ff973797740172e07f8e736ca 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1021,4 +1021,41 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return getHandle().spawnReason; + } + // Paper end - entity spawn reason API ++ ++ // Paper start - entity liquid API ++ @Override ++ public boolean isUnderWater() { ++ return getHandle().isUnderWater(); ++ } ++ ++ @Override ++ public boolean isInRain() { ++ return getHandle().isInRain(); ++ } ++ ++ @Override ++ public boolean isInBubbleColumn() { ++ return getHandle().isInBubbleColumn(); ++ } ++ ++ @Override ++ public boolean isInWaterOrRain() { ++ return getHandle().isInWaterOrRain(); ++ } ++ ++ @Override ++ public boolean isInWaterOrBubbleColumn() { ++ return getHandle().isInWaterOrBubble(); ++ } ++ ++ @Override ++ public boolean isInWaterOrRainOrBubbleColumn() { ++ return getHandle().isInWaterRainOrBubble(); ++ } ++ ++ @Override ++ public boolean isInLava() { ++ return getHandle().isInLava(); ++ } ++ // Paper end - entity liquid API + } diff --git a/patches/server/0374-Improve-fix-EntityTargetLivingEntityEvent.patch b/patches/server/0374-Improve-fix-EntityTargetLivingEntityEvent.patch deleted file mode 100644 index 2777b41e11..0000000000 --- a/patches/server/0374-Improve-fix-EntityTargetLivingEntityEvent.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 9 Dec 2022 03:10:23 -0800 -Subject: [PATCH] Improve/fix EntityTargetLivingEntityEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java -index 70df68169b17fa5f732e4c73a86376ba6eb9ca13..b31f6ccc95132a7dd022b454d28814b684d99d4c 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java -@@ -46,9 +46,22 @@ public class StopAttackingIfTargetInvalid { - if (entityinsentient.canAttack(entityliving) && (!shouldForgetIfTargetUnreachable || !StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) && entityliving.isAlive() && entityliving.level() == entityinsentient.level() && !condition.test(worldserver, entityliving)) { - return true; - } else { -+ // Paper start - better track target change reason -+ final EntityTargetEvent.TargetReason reason; -+ if (!entityinsentient.canAttack(entityliving)) { -+ reason = EntityTargetEvent.TargetReason.TARGET_INVALID; -+ } else if (shouldForgetIfTargetUnreachable && StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) { -+ reason = EntityTargetEvent.TargetReason.FORGOT_TARGET; -+ } else if (!entityliving.isAlive()) { -+ reason = EntityTargetEvent.TargetReason.TARGET_DIED; -+ } else if (entityliving.level() != entityinsentient.level()) { -+ reason = EntityTargetEvent.TargetReason.TARGET_OTHER_LEVEL; -+ } else { -+ reason = EntityTargetEvent.TargetReason.TARGET_INVALID; -+ } -+ // Paper end - // CraftBukkit start -- LivingEntity old = entityinsentient.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null); -- EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, null, (old != null && !old.isAlive()) ? EntityTargetEvent.TargetReason.TARGET_DIED : EntityTargetEvent.TargetReason.FORGOT_TARGET); -+ EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, null, reason); // Paper - if (event.isCancelled()) { - return false; - } diff --git a/patches/server/0375-Add-PrepareResultEvent.patch b/patches/server/0375-Add-PrepareResultEvent.patch new file mode 100644 index 0000000000..50383f0c23 --- /dev/null +++ b/patches/server/0375-Add-PrepareResultEvent.patch @@ -0,0 +1,165 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 3 Jul 2020 11:58:56 -0500 +Subject: [PATCH] Add PrepareResultEvent + +Adds a new event for all crafting stations that generate a result slot item + +Anvil, Grindstone and Smithing now extend this event + +diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java +index dff005cc860fc5ff0759d6e35502deebd00943ed..ae0ba6b0e1f0bee3c3a701b22725171e499b97a3 100644 +--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java +@@ -333,6 +333,7 @@ public class AnvilMenu extends ItemCombinerMenu { + } + + this.createResult(); ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent + return true; + } else { + return false; +diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java +index 5b31d09b158c694b3e54ab3a228817accaa00a0c..8b72d1fd551dcb113f4137aee441a9531c00288a 100644 +--- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java +@@ -140,6 +140,7 @@ public class CartographyTableMenu extends AbstractContainerMenu { + this.setupResultSlot(itemstack, itemstack1, itemstack2); + } + ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent + } + + private void setupResultSlot(ItemStack map, ItemStack item, ItemStack oldResult) { +diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java +index 13bc52bc856031c930370828b0381e43920aabd2..8e58dbb4b110338dfe8add26697d0b1c9ec5fa9c 100644 +--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java +@@ -148,6 +148,7 @@ public class GrindstoneMenu extends AbstractContainerMenu { + super.slotsChanged(inventory); + if (inventory == this.repairSlots) { + this.createResult(); ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent + } + + } +diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java +index 594a387d7e3a67da02ea54b4f259426df2eb21a2..4734dd90f2a66e1ac7a64b35ecd62a630108cf07 100644 +--- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java +@@ -96,6 +96,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { + super.slotsChanged(inventory); + if (inventory == this.inputSlots) { + this.createResult(); ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, this instanceof SmithingMenu ? 3 : 2); // Paper - Add PrepareResultEvent + } + + } +diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java +index d988747ccb81ca74db8ce14fea49d13c9c1b4476..58470d8e9a4ceb1eca05b342481ed8260588e225 100644 +--- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java +@@ -237,7 +237,8 @@ public class LoomMenu extends AbstractContainerMenu { + this.resultSlot.set(ItemStack.EMPTY); + } + +- this.broadcastChanges(); ++ // this.broadcastChanges(); // Paper - Add PrepareResultEvent; done below ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 3); // Paper - Add PrepareResultEvent + } else { + this.resultSlot.set(ItemStack.EMPTY); + this.selectablePatterns = List.of(); +diff --git a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java +index 4b0d07a22cb922aa5ef0c99279663158a5918f1f..89d2f26504bb072c2d75af4ec600ca123e10a600 100644 +--- a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java +@@ -115,6 +115,7 @@ public class SmithingMenu extends ItemCombinerMenu { + this.hasRecipeError.set(flag ? 1 : 0); + } + ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent + } + + @Override +diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java +index 01df301bdacd02255dd00b7dc8b5ea0359d4174a..46d6bc61ba54ab23eb35915073cfd5a3ab0111f1 100644 +--- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java +@@ -174,6 +174,7 @@ public class StonecutterMenu extends AbstractContainerMenu { + this.setupRecipeList(itemstack); + } + ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent + } + + private void setupRecipeList(ItemStack stack) { +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index b8e1a7251f9fa09f03b00b387013af1c623a1e52..f8ec0bca1683d172bc673afc28cf9f7b76e26130 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1679,6 +1679,12 @@ public class CraftEventFactory { + } + + public static PrepareAnvilEvent callPrepareAnvilEvent(AnvilView view, ItemStack item) { ++ // Paper start - Add PrepareResultEvent ++ if (true) { ++ view.getTopInventory().setItem(net.minecraft.world.inventory.AnvilMenu.RESULT_SLOT, CraftItemStack.asCraftMirror(item)); ++ return null; // verify nothing uses return - disable event: handled below in PrepareResult ++ } ++ // Paper end - Add PrepareResultEvent + PrepareAnvilEvent event = new PrepareAnvilEvent(view, CraftItemStack.asCraftMirror(item).clone()); + event.getView().getPlayer().getServer().getPluginManager().callEvent(event); + event.getInventory().setItem(2, event.getResult()); +@@ -1686,6 +1692,12 @@ public class CraftEventFactory { + } + + public static PrepareGrindstoneEvent callPrepareGrindstoneEvent(InventoryView view, ItemStack item) { ++ // Paper start - Add PrepareResultEvent ++ if (true) { ++ view.getTopInventory().setItem(net.minecraft.world.inventory.GrindstoneMenu.RESULT_SLOT, CraftItemStack.asCraftMirror(item)); ++ return null; // verify nothing uses return - disable event: handled below in PrepareResult ++ } ++ // Paper end - Add PrepareResultEvent + PrepareGrindstoneEvent event = new PrepareGrindstoneEvent(view, CraftItemStack.asCraftMirror(item).clone()); + event.getView().getPlayer().getServer().getPluginManager().callEvent(event); + event.getInventory().setItem(2, event.getResult()); +@@ -1693,12 +1705,39 @@ public class CraftEventFactory { + } + + public static PrepareSmithingEvent callPrepareSmithingEvent(InventoryView view, ItemStack item) { ++ // Paper start - Add PrepareResultEvent ++ if (true) { ++ view.getTopInventory().setItem(net.minecraft.world.inventory.SmithingMenu.RESULT_SLOT, CraftItemStack.asCraftMirror(item)); ++ return null; // verify nothing uses return - disable event: handled below in PrepareResult ++ } ++ // Paper end - Add PrepareResultEvent + PrepareSmithingEvent event = new PrepareSmithingEvent(view, CraftItemStack.asCraftMirror(item).clone()); + event.getView().getPlayer().getServer().getPluginManager().callEvent(event); + event.getInventory().setResult(event.getResult()); + return event; + } + ++ // Paper start - Add PrepareResultEvent ++ public static void callPrepareResultEvent(AbstractContainerMenu container, int resultSlot) { ++ final com.destroystokyo.paper.event.inventory.PrepareResultEvent event; ++ InventoryView view = container.getBukkitView(); ++ org.bukkit.inventory.ItemStack origItem = view.getTopInventory().getItem(resultSlot); ++ CraftItemStack result = origItem != null ? CraftItemStack.asCraftCopy(origItem) : null; ++ if (view.getTopInventory() instanceof org.bukkit.inventory.AnvilInventory && view instanceof AnvilView anvilView) { ++ event = new PrepareAnvilEvent(anvilView, result); ++ } else if (view.getTopInventory() instanceof org.bukkit.inventory.GrindstoneInventory) { ++ event = new PrepareGrindstoneEvent(view, result); ++ } else if (view.getTopInventory() instanceof org.bukkit.inventory.SmithingInventory) { ++ event = new PrepareSmithingEvent(view, result); ++ } else { ++ event = new com.destroystokyo.paper.event.inventory.PrepareResultEvent(view, result); ++ } ++ event.callEvent(); ++ event.getInventory().setItem(resultSlot, event.getResult()); ++ container.broadcastChanges();; ++ } ++ // Paper end - Add PrepareResultEvent ++ + /** + * Mob spawner event. + */ diff --git a/patches/server/0375-Add-entity-liquid-API.patch b/patches/server/0375-Add-entity-liquid-API.patch deleted file mode 100644 index e7b8d36eb5..0000000000 --- a/patches/server/0375-Add-entity-liquid-API.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 2 Jul 2020 18:11:43 -0500 -Subject: [PATCH] Add entity liquid API - -== AT == -public net.minecraft.world.entity.Entity isInRain()Z -public net.minecraft.world.entity.Entity isInBubbleColumn()Z - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 73788d702a0a814fe7b1e64b33a3b97ca1777662..ec122fa4e443290ff973797740172e07f8e736ca 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1021,4 +1021,41 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return getHandle().spawnReason; - } - // Paper end - entity spawn reason API -+ -+ // Paper start - entity liquid API -+ @Override -+ public boolean isUnderWater() { -+ return getHandle().isUnderWater(); -+ } -+ -+ @Override -+ public boolean isInRain() { -+ return getHandle().isInRain(); -+ } -+ -+ @Override -+ public boolean isInBubbleColumn() { -+ return getHandle().isInBubbleColumn(); -+ } -+ -+ @Override -+ public boolean isInWaterOrRain() { -+ return getHandle().isInWaterOrRain(); -+ } -+ -+ @Override -+ public boolean isInWaterOrBubbleColumn() { -+ return getHandle().isInWaterOrBubble(); -+ } -+ -+ @Override -+ public boolean isInWaterOrRainOrBubbleColumn() { -+ return getHandle().isInWaterRainOrBubble(); -+ } -+ -+ @Override -+ public boolean isInLava() { -+ return getHandle().isInLava(); -+ } -+ // Paper end - entity liquid API - } diff --git a/patches/server/0376-Add-PrepareResultEvent.patch b/patches/server/0376-Add-PrepareResultEvent.patch deleted file mode 100644 index 50383f0c23..0000000000 --- a/patches/server/0376-Add-PrepareResultEvent.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 3 Jul 2020 11:58:56 -0500 -Subject: [PATCH] Add PrepareResultEvent - -Adds a new event for all crafting stations that generate a result slot item - -Anvil, Grindstone and Smithing now extend this event - -diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -index dff005cc860fc5ff0759d6e35502deebd00943ed..ae0ba6b0e1f0bee3c3a701b22725171e499b97a3 100644 ---- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -@@ -333,6 +333,7 @@ public class AnvilMenu extends ItemCombinerMenu { - } - - this.createResult(); -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent - return true; - } else { - return false; -diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java -index 5b31d09b158c694b3e54ab3a228817accaa00a0c..8b72d1fd551dcb113f4137aee441a9531c00288a 100644 ---- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java -@@ -140,6 +140,7 @@ public class CartographyTableMenu extends AbstractContainerMenu { - this.setupResultSlot(itemstack, itemstack1, itemstack2); - } - -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent - } - - private void setupResultSlot(ItemStack map, ItemStack item, ItemStack oldResult) { -diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -index 13bc52bc856031c930370828b0381e43920aabd2..8e58dbb4b110338dfe8add26697d0b1c9ec5fa9c 100644 ---- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -@@ -148,6 +148,7 @@ public class GrindstoneMenu extends AbstractContainerMenu { - super.slotsChanged(inventory); - if (inventory == this.repairSlots) { - this.createResult(); -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent - } - - } -diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -index 594a387d7e3a67da02ea54b4f259426df2eb21a2..4734dd90f2a66e1ac7a64b35ecd62a630108cf07 100644 ---- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -@@ -96,6 +96,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { - super.slotsChanged(inventory); - if (inventory == this.inputSlots) { - this.createResult(); -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, this instanceof SmithingMenu ? 3 : 2); // Paper - Add PrepareResultEvent - } - - } -diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java -index d988747ccb81ca74db8ce14fea49d13c9c1b4476..58470d8e9a4ceb1eca05b342481ed8260588e225 100644 ---- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java -@@ -237,7 +237,8 @@ public class LoomMenu extends AbstractContainerMenu { - this.resultSlot.set(ItemStack.EMPTY); - } - -- this.broadcastChanges(); -+ // this.broadcastChanges(); // Paper - Add PrepareResultEvent; done below -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 3); // Paper - Add PrepareResultEvent - } else { - this.resultSlot.set(ItemStack.EMPTY); - this.selectablePatterns = List.of(); -diff --git a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java -index 4b0d07a22cb922aa5ef0c99279663158a5918f1f..89d2f26504bb072c2d75af4ec600ca123e10a600 100644 ---- a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java -@@ -115,6 +115,7 @@ public class SmithingMenu extends ItemCombinerMenu { - this.hasRecipeError.set(flag ? 1 : 0); - } - -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent - } - - @Override -diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java -index 01df301bdacd02255dd00b7dc8b5ea0359d4174a..46d6bc61ba54ab23eb35915073cfd5a3ab0111f1 100644 ---- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java -@@ -174,6 +174,7 @@ public class StonecutterMenu extends AbstractContainerMenu { - this.setupRecipeList(itemstack); - } - -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent - } - - private void setupRecipeList(ItemStack stack) { -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index b8e1a7251f9fa09f03b00b387013af1c623a1e52..f8ec0bca1683d172bc673afc28cf9f7b76e26130 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1679,6 +1679,12 @@ public class CraftEventFactory { - } - - public static PrepareAnvilEvent callPrepareAnvilEvent(AnvilView view, ItemStack item) { -+ // Paper start - Add PrepareResultEvent -+ if (true) { -+ view.getTopInventory().setItem(net.minecraft.world.inventory.AnvilMenu.RESULT_SLOT, CraftItemStack.asCraftMirror(item)); -+ return null; // verify nothing uses return - disable event: handled below in PrepareResult -+ } -+ // Paper end - Add PrepareResultEvent - PrepareAnvilEvent event = new PrepareAnvilEvent(view, CraftItemStack.asCraftMirror(item).clone()); - event.getView().getPlayer().getServer().getPluginManager().callEvent(event); - event.getInventory().setItem(2, event.getResult()); -@@ -1686,6 +1692,12 @@ public class CraftEventFactory { - } - - public static PrepareGrindstoneEvent callPrepareGrindstoneEvent(InventoryView view, ItemStack item) { -+ // Paper start - Add PrepareResultEvent -+ if (true) { -+ view.getTopInventory().setItem(net.minecraft.world.inventory.GrindstoneMenu.RESULT_SLOT, CraftItemStack.asCraftMirror(item)); -+ return null; // verify nothing uses return - disable event: handled below in PrepareResult -+ } -+ // Paper end - Add PrepareResultEvent - PrepareGrindstoneEvent event = new PrepareGrindstoneEvent(view, CraftItemStack.asCraftMirror(item).clone()); - event.getView().getPlayer().getServer().getPluginManager().callEvent(event); - event.getInventory().setItem(2, event.getResult()); -@@ -1693,12 +1705,39 @@ public class CraftEventFactory { - } - - public static PrepareSmithingEvent callPrepareSmithingEvent(InventoryView view, ItemStack item) { -+ // Paper start - Add PrepareResultEvent -+ if (true) { -+ view.getTopInventory().setItem(net.minecraft.world.inventory.SmithingMenu.RESULT_SLOT, CraftItemStack.asCraftMirror(item)); -+ return null; // verify nothing uses return - disable event: handled below in PrepareResult -+ } -+ // Paper end - Add PrepareResultEvent - PrepareSmithingEvent event = new PrepareSmithingEvent(view, CraftItemStack.asCraftMirror(item).clone()); - event.getView().getPlayer().getServer().getPluginManager().callEvent(event); - event.getInventory().setResult(event.getResult()); - return event; - } - -+ // Paper start - Add PrepareResultEvent -+ public static void callPrepareResultEvent(AbstractContainerMenu container, int resultSlot) { -+ final com.destroystokyo.paper.event.inventory.PrepareResultEvent event; -+ InventoryView view = container.getBukkitView(); -+ org.bukkit.inventory.ItemStack origItem = view.getTopInventory().getItem(resultSlot); -+ CraftItemStack result = origItem != null ? CraftItemStack.asCraftCopy(origItem) : null; -+ if (view.getTopInventory() instanceof org.bukkit.inventory.AnvilInventory && view instanceof AnvilView anvilView) { -+ event = new PrepareAnvilEvent(anvilView, result); -+ } else if (view.getTopInventory() instanceof org.bukkit.inventory.GrindstoneInventory) { -+ event = new PrepareGrindstoneEvent(view, result); -+ } else if (view.getTopInventory() instanceof org.bukkit.inventory.SmithingInventory) { -+ event = new PrepareSmithingEvent(view, result); -+ } else { -+ event = new com.destroystokyo.paper.event.inventory.PrepareResultEvent(view, result); -+ } -+ event.callEvent(); -+ event.getInventory().setItem(resultSlot, event.getResult()); -+ container.broadcastChanges();; -+ } -+ // Paper end - Add PrepareResultEvent -+ - /** - * Mob spawner event. - */ diff --git a/patches/server/0376-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch b/patches/server/0376-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch new file mode 100644 index 0000000000..446ad63d2d --- /dev/null +++ b/patches/server/0376-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 5 Jul 2020 14:59:31 -0400 +Subject: [PATCH] Don't check chunk for portal on world gen entity add + + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index cd54ab0fed100bf1dd7261185ef0f4e5d4433aa7..b742a42b2c86db79fb88399f40e8682afd600507 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3808,7 +3808,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + Entity entity = this.getVehicle(); + + super.stopRiding(suppressCancellation); // Paper - Force entity dismount during teleportation +- if (entity != null && entity != this.getVehicle() && !this.level().isClientSide) { ++ if (entity != null && entity != this.getVehicle() && !this.level().isClientSide && entity.valid) { // Paper - don't process on world gen + this.dismountVehicle(entity); + } + diff --git a/patches/server/0377-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch b/patches/server/0377-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch deleted file mode 100644 index 446ad63d2d..0000000000 --- a/patches/server/0377-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sun, 5 Jul 2020 14:59:31 -0400 -Subject: [PATCH] Don't check chunk for portal on world gen entity add - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index cd54ab0fed100bf1dd7261185ef0f4e5d4433aa7..b742a42b2c86db79fb88399f40e8682afd600507 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3808,7 +3808,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - Entity entity = this.getVehicle(); - - super.stopRiding(suppressCancellation); // Paper - Force entity dismount during teleportation -- if (entity != null && entity != this.getVehicle() && !this.level().isClientSide) { -+ if (entity != null && entity != this.getVehicle() && !this.level().isClientSide && entity.valid) { // Paper - don't process on world gen - this.dismountVehicle(entity); - } - diff --git a/patches/server/0377-Fix-arrows-never-despawning-MC-125757.patch b/patches/server/0377-Fix-arrows-never-despawning-MC-125757.patch new file mode 100644 index 0000000000..dd322f1d86 --- /dev/null +++ b/patches/server/0377-Fix-arrows-never-despawning-MC-125757.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Wed, 8 Jul 2020 11:24:30 -0500 +Subject: [PATCH] Fix arrows never despawning MC-125757 + +This forces the despawn counter to start ticking regardless of +state after the arrow has been alive for 200 ticks (10 seconds) +instead of getting stuck in a never despawn state (bubble columns, +etc). + +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 2b4df4e417b5655341a640a1c133457f78338970..6637da7a1c17152e8fc5f0f12d8da55bab6070de 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -244,6 +244,7 @@ public abstract class AbstractArrow extends Projectile { + } + + } else { ++ if (tickCount > 200) this.tickDespawn(); // Paper - tick despawnCounter regardless after 10 seconds + this.inGroundTime = 0; + Vec3 vec3d2 = this.position(); + diff --git a/patches/server/0378-Fix-arrows-never-despawning-MC-125757.patch b/patches/server/0378-Fix-arrows-never-despawning-MC-125757.patch deleted file mode 100644 index 5f3fad60eb..0000000000 --- a/patches/server/0378-Fix-arrows-never-despawning-MC-125757.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 8 Jul 2020 11:24:30 -0500 -Subject: [PATCH] Fix arrows never despawning MC-125757 - -This forces the despawn counter to start ticking regardless of -state after the arrow has been alive for 200 ticks (10 seconds) -instead of getting stuck in a never despawn state (bubble columns, -etc). - -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 a05fc651a952b57a8a2fcb32d26d024875037d38..52765e1b9f5a026e7108ff5a7d97681cdb2870e9 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -244,6 +244,7 @@ public abstract class AbstractArrow extends Projectile { - } - - } else { -+ if (tickCount > 200) this.tickDespawn(); // Paper - tick despawnCounter regardless after 10 seconds - this.inGroundTime = 0; - Vec3 vec3d2 = this.position(); - diff --git a/patches/server/0378-Thread-Safe-Vanilla-Command-permission-checking.patch b/patches/server/0378-Thread-Safe-Vanilla-Command-permission-checking.patch new file mode 100644 index 0000000000..475b277470 --- /dev/null +++ b/patches/server/0378-Thread-Safe-Vanilla-Command-permission-checking.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 11 Jul 2020 03:54:28 -0400 +Subject: [PATCH] Thread Safe Vanilla Command permission checking + +Datapacks check this on load and are built concurrently. This was breaking them badly due +to race conditions. + +Plus, .canUse we want to be safe for async anyways. + +diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +index 14ccd0c8f721e9be7dca8a5dcb8ef95b5cd82731..1f4963bf4681a771130abc1da179819626ecfc1f 100644 +--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java ++++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +@@ -75,10 +75,10 @@ public abstract class CommandNode implements Comparable> { + public synchronized boolean canUse(final S source) { + if (source instanceof CommandSourceStack) { + try { +- ((CommandSourceStack) source).currentCommand = this; ++ ((CommandSourceStack) source).currentCommand.put(Thread.currentThread(), this); // Paper - Thread Safe Vanilla Command permission checking + return this.requirement.test(source); + } finally { +- ((CommandSourceStack) source).currentCommand = null; ++ ((CommandSourceStack) source).currentCommand.remove(Thread.currentThread()); // Paper - Thread Safe Vanilla Command permission checking + } + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java +index 5316f148f3f9128690f019d544e462b042d8d797..f31c5d665678c3163ed4469f8e9d395b890c1bbe 100644 +--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java ++++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java +@@ -66,7 +66,7 @@ public class CommandSourceStack implements ExecutionCommandSource currentCommand = new java.util.concurrent.ConcurrentHashMap<>(); // CraftBukkit // Paper - Thread Safe Vanilla Command permission checking + public boolean bypassSelectorPermissions = false; // Paper - add bypass for selector permissions + + public CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity) { +@@ -195,9 +195,11 @@ public class CommandSourceStack implements ExecutionCommandSource +Date: Fri, 10 Jul 2020 13:12:33 -0500 +Subject: [PATCH] Fix SPIGOT-5824 Bukkit world-container is not used + + +diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java +index 577140660c96da69f68ec27ad5ab7da2c836974b..57032ca3e14cd1c64c6436d8b7bca54bfbcee5a9 100644 +--- a/src/main/java/net/minecraft/server/Main.java ++++ b/src/main/java/net/minecraft/server/Main.java +@@ -169,8 +169,17 @@ public class Main { + return; + } + +- File file = (File) optionset.valueOf("universe"); // CraftBukkit +- Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper - pass OptionSet to load paper config files; override authentication service ++ // Paper start - fix SPIGOT-5824 ++ File file; ++ File userCacheFile = new File(Services.USERID_CACHE_FILE); ++ if (optionset.has("universe")) { ++ file = (File) optionset.valueOf("universe"); // CraftBukkit ++ userCacheFile = new File(file, Services.USERID_CACHE_FILE); ++ } else { ++ file = new File(bukkitConfiguration.getString("settings.world-container", ".")); ++ } ++ // Paper end - fix SPIGOT-5824 ++ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, userCacheFile, optionset); // Paper - pass OptionSet to load paper config files; override authentication service; fix world-container + // CraftBukkit start + String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName); + LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath()); +diff --git a/src/main/java/net/minecraft/server/Services.java b/src/main/java/net/minecraft/server/Services.java +index 5928e5f1934b8e247ba516595018ed5c633d3b5d..33e3815a0c979609d4c7ab83ad91e87ac07a556d 100644 +--- a/src/main/java/net/minecraft/server/Services.java ++++ b/src/main/java/net/minecraft/server/Services.java +@@ -24,12 +24,12 @@ public record Services( + return java.util.Objects.requireNonNull(this.paperConfigurations); + } + // Paper end - add paper configuration files +- private static final String USERID_CACHE_FILE = "usercache.json"; ++ public static final String USERID_CACHE_FILE = "usercache.json"; // Paper - private -> public + +- public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, joptsimple.OptionSet optionSet) throws Exception { // Paper - add optionset to load paper config files ++ public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, File userCacheFile, joptsimple.OptionSet optionSet) throws Exception { // Paper - add optionset to load paper config files; add userCacheFile parameter + MinecraftSessionService minecraftSessionService = authenticationService.createMinecraftSessionService(); + GameProfileRepository gameProfileRepository = authenticationService.createProfileRepository(); +- GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, new File(rootDirectory, "usercache.json")); ++ GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, userCacheFile); // Paper - use specified user cache file + // Paper start - load paper config files from cli options + final java.nio.file.Path legacyConfigPath = ((File) optionSet.valueOf("paper-settings")).toPath(); + final java.nio.file.Path configDirPath = ((File) optionSet.valueOf("paper-settings-directory")).toPath(); diff --git a/patches/server/0379-Thread-Safe-Vanilla-Command-permission-checking.patch b/patches/server/0379-Thread-Safe-Vanilla-Command-permission-checking.patch deleted file mode 100644 index 475b277470..0000000000 --- a/patches/server/0379-Thread-Safe-Vanilla-Command-permission-checking.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 11 Jul 2020 03:54:28 -0400 -Subject: [PATCH] Thread Safe Vanilla Command permission checking - -Datapacks check this on load and are built concurrently. This was breaking them badly due -to race conditions. - -Plus, .canUse we want to be safe for async anyways. - -diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java -index 14ccd0c8f721e9be7dca8a5dcb8ef95b5cd82731..1f4963bf4681a771130abc1da179819626ecfc1f 100644 ---- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java -+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java -@@ -75,10 +75,10 @@ public abstract class CommandNode implements Comparable> { - public synchronized boolean canUse(final S source) { - if (source instanceof CommandSourceStack) { - try { -- ((CommandSourceStack) source).currentCommand = this; -+ ((CommandSourceStack) source).currentCommand.put(Thread.currentThread(), this); // Paper - Thread Safe Vanilla Command permission checking - return this.requirement.test(source); - } finally { -- ((CommandSourceStack) source).currentCommand = null; -+ ((CommandSourceStack) source).currentCommand.remove(Thread.currentThread()); // Paper - Thread Safe Vanilla Command permission checking - } - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index 5316f148f3f9128690f019d544e462b042d8d797..f31c5d665678c3163ed4469f8e9d395b890c1bbe 100644 ---- a/src/main/java/net/minecraft/commands/CommandSourceStack.java -+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java -@@ -66,7 +66,7 @@ public class CommandSourceStack implements ExecutionCommandSource currentCommand = new java.util.concurrent.ConcurrentHashMap<>(); // CraftBukkit // Paper - Thread Safe Vanilla Command permission checking - public boolean bypassSelectorPermissions = false; // Paper - add bypass for selector permissions - - public CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity) { -@@ -195,9 +195,11 @@ public class CommandSourceStack implements ExecutionCommandSource -Date: Fri, 10 Jul 2020 13:12:33 -0500 -Subject: [PATCH] Fix SPIGOT-5824 Bukkit world-container is not used - - -diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index 577140660c96da69f68ec27ad5ab7da2c836974b..57032ca3e14cd1c64c6436d8b7bca54bfbcee5a9 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -169,8 +169,17 @@ public class Main { - return; - } - -- File file = (File) optionset.valueOf("universe"); // CraftBukkit -- Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper - pass OptionSet to load paper config files; override authentication service -+ // Paper start - fix SPIGOT-5824 -+ File file; -+ File userCacheFile = new File(Services.USERID_CACHE_FILE); -+ if (optionset.has("universe")) { -+ file = (File) optionset.valueOf("universe"); // CraftBukkit -+ userCacheFile = new File(file, Services.USERID_CACHE_FILE); -+ } else { -+ file = new File(bukkitConfiguration.getString("settings.world-container", ".")); -+ } -+ // Paper end - fix SPIGOT-5824 -+ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, userCacheFile, optionset); // Paper - pass OptionSet to load paper config files; override authentication service; fix world-container - // CraftBukkit start - String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName); - LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath()); -diff --git a/src/main/java/net/minecraft/server/Services.java b/src/main/java/net/minecraft/server/Services.java -index 5928e5f1934b8e247ba516595018ed5c633d3b5d..33e3815a0c979609d4c7ab83ad91e87ac07a556d 100644 ---- a/src/main/java/net/minecraft/server/Services.java -+++ b/src/main/java/net/minecraft/server/Services.java -@@ -24,12 +24,12 @@ public record Services( - return java.util.Objects.requireNonNull(this.paperConfigurations); - } - // Paper end - add paper configuration files -- private static final String USERID_CACHE_FILE = "usercache.json"; -+ public static final String USERID_CACHE_FILE = "usercache.json"; // Paper - private -> public - -- public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, joptsimple.OptionSet optionSet) throws Exception { // Paper - add optionset to load paper config files -+ public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, File userCacheFile, joptsimple.OptionSet optionSet) throws Exception { // Paper - add optionset to load paper config files; add userCacheFile parameter - MinecraftSessionService minecraftSessionService = authenticationService.createMinecraftSessionService(); - GameProfileRepository gameProfileRepository = authenticationService.createProfileRepository(); -- GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, new File(rootDirectory, "usercache.json")); -+ GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, userCacheFile); // Paper - use specified user cache file - // Paper start - load paper config files from cli options - final java.nio.file.Path legacyConfigPath = ((File) optionSet.valueOf("paper-settings")).toPath(); - final java.nio.file.Path configDirPath = ((File) optionSet.valueOf("paper-settings-directory")).toPath(); diff --git a/patches/server/0380-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch b/patches/server/0380-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch new file mode 100644 index 0000000000..7b65f71eac --- /dev/null +++ b/patches/server/0380-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 10 Jul 2020 12:38:12 -0500 +Subject: [PATCH] Fix SPIGOT-5885 Unable to disable advancements + + +diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java +index 57032ca3e14cd1c64c6436d8b7bca54bfbcee5a9..da61f3a4ec9bb9726d9d45552b8eada3f87d9e58 100644 +--- a/src/main/java/net/minecraft/server/Main.java ++++ b/src/main/java/net/minecraft/server/Main.java +@@ -169,6 +169,7 @@ public class Main { + return; + } + ++ 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; + File userCacheFile = new File(Services.USERID_CACHE_FILE); diff --git a/patches/server/0381-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch b/patches/server/0381-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch new file mode 100644 index 0000000000..ef009ef823 --- /dev/null +++ b/patches/server/0381-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 13 Jul 2020 06:22:54 -0700 +Subject: [PATCH] Fix AdvancementDataPlayer leak due from quitting early in + login + +Move the criterion storage to the AdvancementDataPlayer object +itself, so the criterion object stores no references - and thus +needs no cleanup. + +diff --git a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java +index 9a387d5dc0925304d4163e3caa22206aaa68e3b7..f43053ba082f9772b6ec02828fa2d6f387c32d26 100644 +--- a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java ++++ b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java +@@ -15,32 +15,32 @@ import net.minecraft.server.level.ServerPlayer; + import net.minecraft.world.level.storage.loot.LootContext; + + public abstract class SimpleCriterionTrigger implements CriterionTrigger { +- private final Map>> players = Maps.newIdentityHashMap(); ++ // private final Map>> players = Maps.newIdentityHashMap(); // Paper - fix AdvancementDataPlayer leak; moved into AdvancementDataPlayer to fix memory leak + + @Override + public final void addPlayerListener(PlayerAdvancements manager, CriterionTrigger.Listener conditions) { +- this.players.computeIfAbsent(manager, managerx -> Sets.newHashSet()).add(conditions); ++ manager.criterionData.computeIfAbsent(this, managerx -> Sets.newHashSet()).add(conditions); // Paper - fix AdvancementDataPlayer leak + } + + @Override + public final void removePlayerListener(PlayerAdvancements manager, CriterionTrigger.Listener conditions) { +- Set> set = this.players.get(manager); ++ Set> set = (Set) manager.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak + if (set != null) { + set.remove(conditions); + if (set.isEmpty()) { +- this.players.remove(manager); ++ manager.criterionData.remove(this); // Paper - fix AdvancementDataPlayer leak + } + } + } + + @Override + public final void removePlayerListeners(PlayerAdvancements tracker) { +- this.players.remove(tracker); ++ tracker.criterionData.remove(this); // Paper - fix AdvancementDataPlayer leak + } + + protected void trigger(ServerPlayer player, Predicate predicate) { + PlayerAdvancements playerAdvancements = player.getAdvancements(); +- Set> set = this.players.get(playerAdvancements); ++ Set> set = (Set) playerAdvancements.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak + if (set != null && !set.isEmpty()) { + LootContext lootContext = EntityPredicate.createContext(player, player); + List> list = null; +diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java +index 0542b61053ed7039e54856eab86ba5842403e4fc..0fe941b0802f2966ad55509baac124f56ecef999 100644 +--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java ++++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java +@@ -63,6 +63,7 @@ public class PlayerAdvancements { + private AdvancementHolder lastSelectedTab; + private boolean isFirstPacket = true; + private final Codec codec; ++ public final Map, Set>> criterionData = new java.util.IdentityHashMap<>(); // Paper - fix advancement data player leakage + + public PlayerAdvancements(DataFixer dataFixer, PlayerList playerManager, ServerAdvancementManager advancementLoader, Path filePath, ServerPlayer owner) { + this.playerList = playerManager; diff --git a/patches/server/0381-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch b/patches/server/0381-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch deleted file mode 100644 index 7b65f71eac..0000000000 --- a/patches/server/0381-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 10 Jul 2020 12:38:12 -0500 -Subject: [PATCH] Fix SPIGOT-5885 Unable to disable advancements - - -diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index 57032ca3e14cd1c64c6436d8b7bca54bfbcee5a9..da61f3a4ec9bb9726d9d45552b8eada3f87d9e58 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -169,6 +169,7 @@ public class Main { - return; - } - -+ 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; - File userCacheFile = new File(Services.USERID_CACHE_FILE); diff --git a/patches/server/0382-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch b/patches/server/0382-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch deleted file mode 100644 index ef009ef823..0000000000 --- a/patches/server/0382-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 13 Jul 2020 06:22:54 -0700 -Subject: [PATCH] Fix AdvancementDataPlayer leak due from quitting early in - login - -Move the criterion storage to the AdvancementDataPlayer object -itself, so the criterion object stores no references - and thus -needs no cleanup. - -diff --git a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -index 9a387d5dc0925304d4163e3caa22206aaa68e3b7..f43053ba082f9772b6ec02828fa2d6f387c32d26 100644 ---- a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -+++ b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -@@ -15,32 +15,32 @@ import net.minecraft.server.level.ServerPlayer; - import net.minecraft.world.level.storage.loot.LootContext; - - public abstract class SimpleCriterionTrigger implements CriterionTrigger { -- private final Map>> players = Maps.newIdentityHashMap(); -+ // private final Map>> players = Maps.newIdentityHashMap(); // Paper - fix AdvancementDataPlayer leak; moved into AdvancementDataPlayer to fix memory leak - - @Override - public final void addPlayerListener(PlayerAdvancements manager, CriterionTrigger.Listener conditions) { -- this.players.computeIfAbsent(manager, managerx -> Sets.newHashSet()).add(conditions); -+ manager.criterionData.computeIfAbsent(this, managerx -> Sets.newHashSet()).add(conditions); // Paper - fix AdvancementDataPlayer leak - } - - @Override - public final void removePlayerListener(PlayerAdvancements manager, CriterionTrigger.Listener conditions) { -- Set> set = this.players.get(manager); -+ Set> set = (Set) manager.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak - if (set != null) { - set.remove(conditions); - if (set.isEmpty()) { -- this.players.remove(manager); -+ manager.criterionData.remove(this); // Paper - fix AdvancementDataPlayer leak - } - } - } - - @Override - public final void removePlayerListeners(PlayerAdvancements tracker) { -- this.players.remove(tracker); -+ tracker.criterionData.remove(this); // Paper - fix AdvancementDataPlayer leak - } - - protected void trigger(ServerPlayer player, Predicate predicate) { - PlayerAdvancements playerAdvancements = player.getAdvancements(); -- Set> set = this.players.get(playerAdvancements); -+ Set> set = (Set) playerAdvancements.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak - if (set != null && !set.isEmpty()) { - LootContext lootContext = EntityPredicate.createContext(player, player); - List> list = null; -diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java -index 0542b61053ed7039e54856eab86ba5842403e4fc..0fe941b0802f2966ad55509baac124f56ecef999 100644 ---- a/src/main/java/net/minecraft/server/PlayerAdvancements.java -+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java -@@ -63,6 +63,7 @@ public class PlayerAdvancements { - private AdvancementHolder lastSelectedTab; - private boolean isFirstPacket = true; - private final Codec codec; -+ public final Map, Set>> criterionData = new java.util.IdentityHashMap<>(); // Paper - fix advancement data player leakage - - public PlayerAdvancements(DataFixer dataFixer, PlayerList playerManager, ServerAdvancementManager advancementLoader, Path filePath, ServerPlayer owner) { - this.playerList = playerManager; diff --git a/patches/server/0382-Optimize-NetworkManager-Exception-Handling.patch b/patches/server/0382-Optimize-NetworkManager-Exception-Handling.patch new file mode 100644 index 0000000000..8626e3b900 --- /dev/null +++ b/patches/server/0382-Optimize-NetworkManager-Exception-Handling.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Steinborn +Date: Sun, 5 Jul 2020 22:38:18 -0400 +Subject: [PATCH] Optimize NetworkManager Exception Handling + + +diff --git a/src/main/java/net/minecraft/network/Varint21FrameDecoder.java b/src/main/java/net/minecraft/network/Varint21FrameDecoder.java +index 421dd76816063d56ea80339b77531729edd6aa55..1523d69b7b332f0085f40310a94d406da6513edc 100644 +--- a/src/main/java/net/minecraft/network/Varint21FrameDecoder.java ++++ b/src/main/java/net/minecraft/network/Varint21FrameDecoder.java +@@ -39,6 +39,12 @@ public class Varint21FrameDecoder extends ByteToMessageDecoder { + } + + protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) { ++ // Paper start - Perf: Optimize exception handling; if channel is not active just discard the packet ++ if (!channelHandlerContext.channel().isActive()) { ++ byteBuf.skipBytes(byteBuf.readableBytes()); ++ return; ++ } ++ // Paper end - Perf: Optimize exception handling + byteBuf.markReaderIndex(); + this.helperBuf.clear(); + if (!copyVarint(byteBuf, this.helperBuf)) { diff --git a/patches/server/0383-Fix-some-rails-connecting-improperly.patch b/patches/server/0383-Fix-some-rails-connecting-improperly.patch new file mode 100644 index 0000000000..c22d4e1fdf --- /dev/null +++ b/patches/server/0383-Fix-some-rails-connecting-improperly.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Fri, 24 Jul 2020 15:56:05 -0700 +Subject: [PATCH] Fix some rails connecting improperly + + +diff --git a/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java b/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java +index 4a5badc4bb1e2c29016735e9df93c7ac4d3f363d..f9a55f76fed8609bca167b2ea37464e8079de0c0 100644 +--- a/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java +@@ -71,6 +71,7 @@ public abstract class BaseRailBlock extends Block implements SimpleWaterloggedBl + state = this.updateDir(world, pos, state, true); + if (this.isStraight) { + world.neighborChanged(state, pos, this, null, notify); ++ state = world.getBlockState(pos); // Paper - Fix some rails connecting improperly + } + + return state; +diff --git a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java +index 3de30845aae143e5be5db921004142792522607d..1e2f56b5c40c3dc72bc38354160f8e7de1f4f5cf 100644 +--- a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java +@@ -78,6 +78,7 @@ public class DetectorRailBlock extends BaseRailBlock { + + private void checkPressed(Level world, BlockPos pos, BlockState state) { + if (this.canSurvive(state, world, pos)) { ++ if (state.getBlock() != this) { return; } // Paper - Fix some rails connecting improperly + boolean flag = (Boolean) state.getValue(DetectorRailBlock.POWERED); + boolean flag1 = false; + List list = this.getInteractingMinecartOfType(world, pos, AbstractMinecart.class, (entity) -> { +diff --git a/src/main/java/net/minecraft/world/level/block/RailState.java b/src/main/java/net/minecraft/world/level/block/RailState.java +index 6caafa73b03ed55c95303e49735eaf3dfd34903a..aa7ebaccad8dc555d9e1dee300e75fcd968a3608 100644 +--- a/src/main/java/net/minecraft/world/level/block/RailState.java ++++ b/src/main/java/net/minecraft/world/level/block/RailState.java +@@ -17,6 +17,12 @@ public class RailState { + private final boolean isStraight; + private final List connections = Lists.newArrayList(); + ++ // Paper start - Fix some rails connecting improperly ++ public boolean isValid() { ++ return this.level.getBlockState(this.pos).getBlock() == this.state.getBlock(); ++ } ++ // Paper end - Fix some rails connecting improperly ++ + public RailState(Level world, BlockPos pos, BlockState state) { + this.level = world; + this.pos = pos; +@@ -141,6 +147,11 @@ public class RailState { + } + + private void connectTo(RailState placementHelper) { ++ // Paper start - Fix some rails connecting improperly ++ if (!this.isValid() || !placementHelper.isValid()) { ++ return; ++ } ++ // Paper end - Fix some rails connecting improperly + this.connections.add(placementHelper.pos); + BlockPos blockPos = this.pos.north(); + BlockPos blockPos2 = this.pos.south(); +@@ -331,10 +342,15 @@ public class RailState { + this.state = this.state.setValue(this.block.getShapeProperty(), railShape2); + if (forceUpdate || this.level.getBlockState(this.pos) != this.state) { + this.level.setBlock(this.pos, this.state, 3); ++ // Paper start - Fix some rails connecting improperly ++ if (!this.isValid()) { ++ return this; ++ } ++ // Paper end - Fix some rails connecting improperly + + for (int i = 0; i < this.connections.size(); i++) { + RailState railState = this.getRail(this.connections.get(i)); +- if (railState != null) { ++ if (railState != null && railState.isValid()) { // Paper - Fix some rails connecting improperly + railState.removeSoftConnections(); + if (railState.canConnectTo(this)) { + railState.connectTo(this); +@@ -347,6 +363,6 @@ public class RailState { + } + + public BlockState getState() { +- return this.state; ++ return this.level.getBlockState(this.pos); // Paper - Fix some rails connecting improperly + } + } diff --git a/patches/server/0383-Optimize-NetworkManager-Exception-Handling.patch b/patches/server/0383-Optimize-NetworkManager-Exception-Handling.patch deleted file mode 100644 index 8626e3b900..0000000000 --- a/patches/server/0383-Optimize-NetworkManager-Exception-Handling.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrew Steinborn -Date: Sun, 5 Jul 2020 22:38:18 -0400 -Subject: [PATCH] Optimize NetworkManager Exception Handling - - -diff --git a/src/main/java/net/minecraft/network/Varint21FrameDecoder.java b/src/main/java/net/minecraft/network/Varint21FrameDecoder.java -index 421dd76816063d56ea80339b77531729edd6aa55..1523d69b7b332f0085f40310a94d406da6513edc 100644 ---- a/src/main/java/net/minecraft/network/Varint21FrameDecoder.java -+++ b/src/main/java/net/minecraft/network/Varint21FrameDecoder.java -@@ -39,6 +39,12 @@ public class Varint21FrameDecoder extends ByteToMessageDecoder { - } - - protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) { -+ // Paper start - Perf: Optimize exception handling; if channel is not active just discard the packet -+ if (!channelHandlerContext.channel().isActive()) { -+ byteBuf.skipBytes(byteBuf.readableBytes()); -+ return; -+ } -+ // Paper end - Perf: Optimize exception handling - byteBuf.markReaderIndex(); - this.helperBuf.clear(); - if (!copyVarint(byteBuf, this.helperBuf)) { diff --git a/patches/server/0384-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch b/patches/server/0384-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch new file mode 100644 index 0000000000..75cd32bb83 --- /dev/null +++ b/patches/server/0384-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: mbax +Date: Mon, 17 Aug 2020 12:17:37 -0400 +Subject: [PATCH] Fix regex mistake in CB NBT int deserialization + +The existing regex is too open and allows for the absence of any actual +number data, detecting an NBT entry of just the letter "i" in upper or +lower case. This causes a single-character NBT entry to be processed as +an integer ending in "i", passing an empty String to to Integer.parseInt, +triggering an exception in loading the item. + +This commit forces numbers to be present prior to the ending "i" +letter. + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java +index be9686a4240acf24a9ee022cff6ba848524b4498..1d282b1f3cf968364474ce5700bc95ebc46b9f1c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java +@@ -18,7 +18,7 @@ import org.jetbrains.annotations.NotNull; + public class CraftNBTTagConfigSerializer { + + private static final Pattern ARRAY = Pattern.compile("^\\[.*]"); +- private static final Pattern INTEGER = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)?i", Pattern.CASE_INSENSITIVE); ++ private static final Pattern INTEGER = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)i", Pattern.CASE_INSENSITIVE); // Paper - fix regex + private static final Pattern DOUBLE = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", Pattern.CASE_INSENSITIVE); + private static final TagParser MOJANGSON_PARSER = new TagParser(new StringReader("")); + diff --git a/patches/server/0384-Fix-some-rails-connecting-improperly.patch b/patches/server/0384-Fix-some-rails-connecting-improperly.patch deleted file mode 100644 index c22d4e1fdf..0000000000 --- a/patches/server/0384-Fix-some-rails-connecting-improperly.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Fri, 24 Jul 2020 15:56:05 -0700 -Subject: [PATCH] Fix some rails connecting improperly - - -diff --git a/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java b/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java -index 4a5badc4bb1e2c29016735e9df93c7ac4d3f363d..f9a55f76fed8609bca167b2ea37464e8079de0c0 100644 ---- a/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BaseRailBlock.java -@@ -71,6 +71,7 @@ public abstract class BaseRailBlock extends Block implements SimpleWaterloggedBl - state = this.updateDir(world, pos, state, true); - if (this.isStraight) { - world.neighborChanged(state, pos, this, null, notify); -+ state = world.getBlockState(pos); // Paper - Fix some rails connecting improperly - } - - return state; -diff --git a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java -index 3de30845aae143e5be5db921004142792522607d..1e2f56b5c40c3dc72bc38354160f8e7de1f4f5cf 100644 ---- a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java -@@ -78,6 +78,7 @@ public class DetectorRailBlock extends BaseRailBlock { - - private void checkPressed(Level world, BlockPos pos, BlockState state) { - if (this.canSurvive(state, world, pos)) { -+ if (state.getBlock() != this) { return; } // Paper - Fix some rails connecting improperly - boolean flag = (Boolean) state.getValue(DetectorRailBlock.POWERED); - boolean flag1 = false; - List list = this.getInteractingMinecartOfType(world, pos, AbstractMinecart.class, (entity) -> { -diff --git a/src/main/java/net/minecraft/world/level/block/RailState.java b/src/main/java/net/minecraft/world/level/block/RailState.java -index 6caafa73b03ed55c95303e49735eaf3dfd34903a..aa7ebaccad8dc555d9e1dee300e75fcd968a3608 100644 ---- a/src/main/java/net/minecraft/world/level/block/RailState.java -+++ b/src/main/java/net/minecraft/world/level/block/RailState.java -@@ -17,6 +17,12 @@ public class RailState { - private final boolean isStraight; - private final List connections = Lists.newArrayList(); - -+ // Paper start - Fix some rails connecting improperly -+ public boolean isValid() { -+ return this.level.getBlockState(this.pos).getBlock() == this.state.getBlock(); -+ } -+ // Paper end - Fix some rails connecting improperly -+ - public RailState(Level world, BlockPos pos, BlockState state) { - this.level = world; - this.pos = pos; -@@ -141,6 +147,11 @@ public class RailState { - } - - private void connectTo(RailState placementHelper) { -+ // Paper start - Fix some rails connecting improperly -+ if (!this.isValid() || !placementHelper.isValid()) { -+ return; -+ } -+ // Paper end - Fix some rails connecting improperly - this.connections.add(placementHelper.pos); - BlockPos blockPos = this.pos.north(); - BlockPos blockPos2 = this.pos.south(); -@@ -331,10 +342,15 @@ public class RailState { - this.state = this.state.setValue(this.block.getShapeProperty(), railShape2); - if (forceUpdate || this.level.getBlockState(this.pos) != this.state) { - this.level.setBlock(this.pos, this.state, 3); -+ // Paper start - Fix some rails connecting improperly -+ if (!this.isValid()) { -+ return this; -+ } -+ // Paper end - Fix some rails connecting improperly - - for (int i = 0; i < this.connections.size(); i++) { - RailState railState = this.getRail(this.connections.get(i)); -- if (railState != null) { -+ if (railState != null && railState.isValid()) { // Paper - Fix some rails connecting improperly - railState.removeSoftConnections(); - if (railState.canConnectTo(this)) { - railState.connectTo(this); -@@ -347,6 +363,6 @@ public class RailState { - } - - public BlockState getState() { -- return this.state; -+ return this.level.getBlockState(this.pos); // Paper - Fix some rails connecting improperly - } - } diff --git a/patches/server/0385-Brand-support.patch b/patches/server/0385-Brand-support.patch new file mode 100644 index 0000000000..623e6bf4e9 --- /dev/null +++ b/patches/server/0385-Brand-support.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DigitalRegent +Date: Sat, 11 Apr 2020 13:10:58 +0200 +Subject: [PATCH] Brand support + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index b1340a5021991d09a0f4a6ad4ce5d7389feb1175..ed2164d8c652b135f9cb777f1a6242bcfec36bbc 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -320,6 +320,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + // CraftBukkit end + public boolean isRealPlayer; // Paper + public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent ++ public @Nullable String clientBrandName = null; // Paper - Brand support + + public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { + super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); +diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +index b9fbaddcc8239bf737fdea51790f678306e511eb..9a8b08d4b70b8890961e4af7ce6e870aa1c7c810 100644 +--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +@@ -84,6 +84,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + private volatile boolean suspendFlushingOnServerThread = false; + public final java.util.Map packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks + private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit ++ protected static final ResourceLocation MINECRAFT_BRAND = ResourceLocation.withDefaultNamespace("brand"); // Paper - Brand support + + public ServerCommonPacketListenerImpl(MinecraftServer minecraftserver, Connection networkmanager, CommonListenerCookie commonlistenercookie, ServerPlayer player) { // CraftBukkit + this.server = minecraftserver; +@@ -155,6 +156,11 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + + @Override + public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { ++ // Paper start - Brand support ++ if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.BrandPayload brandPayload) { ++ this.player.clientBrandName = brandPayload.brand(); ++ } ++ // Paper end - Brand support + if (!(packet.payload() instanceof DiscardedPayload)) { + return; + } +@@ -186,6 +192,15 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + try { + byte[] data = new byte[payload.readableBytes()]; + payload.readBytes(data); ++ // Paper start - Brand support; Retain this incase upstream decides to 'break' the new mechanism in favour of backwards compat... ++ if (identifier.equals(MINECRAFT_BRAND)) { ++ try { ++ this.player.clientBrandName = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.copiedBuffer(data)).readUtf(256); ++ } catch (StringIndexOutOfBoundsException ex) { ++ this.player.clientBrandName = "illegal"; ++ } ++ } ++ // Paper end - Brand support + this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), identifier.toString(), data); + } catch (Exception ex) { + ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t dispatch custom payload", ex); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 589c78cf8acc8868be686123ac893421b4848239..42ee772b76b7601ad59378c81277fe0c60e4438b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -3141,6 +3141,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + // Paper end + }; + ++ // Paper start - brand support ++ @Override ++ public String getClientBrandName() { ++ return getHandle().clientBrandName; ++ } ++ // Paper end ++ + public Player.Spigot spigot() + { + return this.spigot; diff --git a/patches/server/0385-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch b/patches/server/0385-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch deleted file mode 100644 index 75cd32bb83..0000000000 --- a/patches/server/0385-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: mbax -Date: Mon, 17 Aug 2020 12:17:37 -0400 -Subject: [PATCH] Fix regex mistake in CB NBT int deserialization - -The existing regex is too open and allows for the absence of any actual -number data, detecting an NBT entry of just the letter "i" in upper or -lower case. This causes a single-character NBT entry to be processed as -an integer ending in "i", passing an empty String to to Integer.parseInt, -triggering an exception in loading the item. - -This commit forces numbers to be present prior to the ending "i" -letter. - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java -index be9686a4240acf24a9ee022cff6ba848524b4498..1d282b1f3cf968364474ce5700bc95ebc46b9f1c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java -@@ -18,7 +18,7 @@ import org.jetbrains.annotations.NotNull; - public class CraftNBTTagConfigSerializer { - - private static final Pattern ARRAY = Pattern.compile("^\\[.*]"); -- private static final Pattern INTEGER = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)?i", Pattern.CASE_INSENSITIVE); -+ private static final Pattern INTEGER = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)i", Pattern.CASE_INSENSITIVE); // Paper - fix regex - private static final Pattern DOUBLE = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", Pattern.CASE_INSENSITIVE); - private static final TagParser MOJANGSON_PARSER = new TagParser(new StringReader("")); - diff --git a/patches/server/0386-Add-playPickupItemAnimation-to-LivingEntity.patch b/patches/server/0386-Add-playPickupItemAnimation-to-LivingEntity.patch new file mode 100644 index 0000000000..5b48b5baca --- /dev/null +++ b/patches/server/0386-Add-playPickupItemAnimation-to-LivingEntity.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 23 Aug 2020 19:36:22 +0200 +Subject: [PATCH] Add playPickupItemAnimation to LivingEntity + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 1873b5c22d3b351b6120cb832c6ff045d9ad38f0..0aa3fd9dce0cf90b1f74551c864e9ebf326eb1f3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -1009,4 +1009,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + } + } + // Paper end - entity jump API ++ ++ // Paper start - pickup animation API ++ @Override ++ public void playPickupItemAnimation(final org.bukkit.entity.Item item, final int quantity) { ++ this.getHandle().take(((CraftItem) item).getHandle(), quantity); ++ } ++ // Paper end - pickup animation API + } diff --git a/patches/server/0386-Brand-support.patch b/patches/server/0386-Brand-support.patch deleted file mode 100644 index 7fe7a24ff5..0000000000 --- a/patches/server/0386-Brand-support.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DigitalRegent -Date: Sat, 11 Apr 2020 13:10:58 +0200 -Subject: [PATCH] Brand support - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 07b1bc1a06ac1fec83ba76a73b3cc1bd8f560208..475ad396d842617b53ccf59fd07bfe1682852e50 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -320,6 +320,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - // CraftBukkit end - public boolean isRealPlayer; // Paper - public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent -+ public @Nullable String clientBrandName = null; // Paper - Brand support - - public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { - super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); -diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index b9fbaddcc8239bf737fdea51790f678306e511eb..9a8b08d4b70b8890961e4af7ce6e870aa1c7c810 100644 ---- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -84,6 +84,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - private volatile boolean suspendFlushingOnServerThread = false; - public final java.util.Map packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks - private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit -+ protected static final ResourceLocation MINECRAFT_BRAND = ResourceLocation.withDefaultNamespace("brand"); // Paper - Brand support - - public ServerCommonPacketListenerImpl(MinecraftServer minecraftserver, Connection networkmanager, CommonListenerCookie commonlistenercookie, ServerPlayer player) { // CraftBukkit - this.server = minecraftserver; -@@ -155,6 +156,11 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - - @Override - public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { -+ // Paper start - Brand support -+ if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.BrandPayload brandPayload) { -+ this.player.clientBrandName = brandPayload.brand(); -+ } -+ // Paper end - Brand support - if (!(packet.payload() instanceof DiscardedPayload)) { - return; - } -@@ -186,6 +192,15 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - try { - byte[] data = new byte[payload.readableBytes()]; - payload.readBytes(data); -+ // Paper start - Brand support; Retain this incase upstream decides to 'break' the new mechanism in favour of backwards compat... -+ if (identifier.equals(MINECRAFT_BRAND)) { -+ try { -+ this.player.clientBrandName = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.copiedBuffer(data)).readUtf(256); -+ } catch (StringIndexOutOfBoundsException ex) { -+ this.player.clientBrandName = "illegal"; -+ } -+ } -+ // Paper end - Brand support - this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), identifier.toString(), data); - } catch (Exception ex) { - ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t dispatch custom payload", ex); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 589c78cf8acc8868be686123ac893421b4848239..42ee772b76b7601ad59378c81277fe0c60e4438b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3141,6 +3141,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - // Paper end - }; - -+ // Paper start - brand support -+ @Override -+ public String getClientBrandName() { -+ return getHandle().clientBrandName; -+ } -+ // Paper end -+ - public Player.Spigot spigot() - { - return this.spigot; diff --git a/patches/server/0387-Add-playPickupItemAnimation-to-LivingEntity.patch b/patches/server/0387-Add-playPickupItemAnimation-to-LivingEntity.patch deleted file mode 100644 index 5b48b5baca..0000000000 --- a/patches/server/0387-Add-playPickupItemAnimation-to-LivingEntity.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 23 Aug 2020 19:36:22 +0200 -Subject: [PATCH] Add playPickupItemAnimation to LivingEntity - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 1873b5c22d3b351b6120cb832c6ff045d9ad38f0..0aa3fd9dce0cf90b1f74551c864e9ebf326eb1f3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -1009,4 +1009,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - } - } - // Paper end - entity jump API -+ -+ // Paper start - pickup animation API -+ @Override -+ public void playPickupItemAnimation(final org.bukkit.entity.Item item, final int quantity) { -+ this.getHandle().take(((CraftItem) item).getHandle(), quantity); -+ } -+ // Paper end - pickup animation API - } diff --git a/patches/server/0387-Don-t-require-FACING-data.patch b/patches/server/0387-Don-t-require-FACING-data.patch new file mode 100644 index 0000000000..2cec1e5276 --- /dev/null +++ b/patches/server/0387-Don-t-require-FACING-data.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sun, 23 Aug 2020 19:01:04 +0200 +Subject: [PATCH] Don't require FACING data + + +diff --git a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java +index c90bce6777d24821758d1830e6c6c6c72e19703f..39c96f5db6e90a470404c6387fa0c1d5531822e5 100644 +--- a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java +@@ -14,6 +14,7 @@ import org.bukkit.event.block.BlockDispenseEvent; + // CraftBukkit end + + public class DefaultDispenseItemBehavior implements DispenseItemBehavior { ++ private Direction enumdirection; // Paper - cache facing direction + + private static final int DEFAULT_ACCURACY = 6; + +@@ -29,15 +30,16 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior { + + @Override + public final ItemStack dispense(BlockSource pointer, ItemStack stack) { ++ enumdirection = pointer.state().getValue(DispenserBlock.FACING); // Paper - cache facing direction + ItemStack itemstack1 = this.execute(pointer, stack); + + this.playSound(pointer); +- this.playAnimation(pointer, (Direction) pointer.state().getValue(DispenserBlock.FACING)); ++ this.playAnimation(pointer, enumdirection); // Paper - cache facing direction + return itemstack1; + } + + protected ItemStack execute(BlockSource pointer, ItemStack stack) { +- Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); ++ // Paper - cached enum direction + Position iposition = DispenserBlock.getDispensePosition(pointer); + ItemStack itemstack1 = stack.split(1); + diff --git a/patches/server/0388-Don-t-require-FACING-data.patch b/patches/server/0388-Don-t-require-FACING-data.patch deleted file mode 100644 index 2cec1e5276..0000000000 --- a/patches/server/0388-Don-t-require-FACING-data.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sun, 23 Aug 2020 19:01:04 +0200 -Subject: [PATCH] Don't require FACING data - - -diff --git a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -index c90bce6777d24821758d1830e6c6c6c72e19703f..39c96f5db6e90a470404c6387fa0c1d5531822e5 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -@@ -14,6 +14,7 @@ import org.bukkit.event.block.BlockDispenseEvent; - // CraftBukkit end - - public class DefaultDispenseItemBehavior implements DispenseItemBehavior { -+ private Direction enumdirection; // Paper - cache facing direction - - private static final int DEFAULT_ACCURACY = 6; - -@@ -29,15 +30,16 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior { - - @Override - public final ItemStack dispense(BlockSource pointer, ItemStack stack) { -+ enumdirection = pointer.state().getValue(DispenserBlock.FACING); // Paper - cache facing direction - ItemStack itemstack1 = this.execute(pointer, stack); - - this.playSound(pointer); -- this.playAnimation(pointer, (Direction) pointer.state().getValue(DispenserBlock.FACING)); -+ this.playAnimation(pointer, enumdirection); // Paper - cache facing direction - return itemstack1; - } - - protected ItemStack execute(BlockSource pointer, ItemStack stack) { -- Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING); -+ // Paper - cached enum direction - Position iposition = DispenserBlock.getDispensePosition(pointer); - ItemStack itemstack1 = stack.split(1); - diff --git a/patches/server/0388-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch b/patches/server/0388-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch new file mode 100644 index 0000000000..152014d89c --- /dev/null +++ b/patches/server/0388-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 22 Aug 2020 23:36:21 +0200 +Subject: [PATCH] Fix SpawnChangeEvent not firing for all use-cases + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index c631ea4e75798e36cc6418b1e71eeca89c8263d5..d32606cba7222aa538cca3882314f9f87f33684f 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1715,7 +1715,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + float f1 = this.levelData.getSpawnAngle(); + + if (!blockposition1.equals(pos) || f1 != angle) { ++ org.bukkit.Location prevSpawnLoc = this.getWorld().getSpawnLocation(); // Paper - Call SpawnChangeEvent + this.levelData.setSpawn(pos, angle); ++ new org.bukkit.event.world.SpawnChangeEvent(this.getWorld(), prevSpawnLoc).callEvent(); // Paper - Call SpawnChangeEvent + this.getServer().getPlayerList().broadcastAll(new ClientboundSetDefaultSpawnPositionPacket(pos, angle)); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 031c46e8cf1c49c4db2887dc32cbad75532f8faa..b877904bd18c96a4a7e49fb3e1aba2b6109f15cd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -243,12 +243,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + public boolean setSpawnLocation(int x, int y, int z, float angle) { + try { +- Location previousLocation = this.getSpawnLocation(); +- this.world.levelData.setSpawn(new BlockPos(x, y, z), angle); ++ // Location previousLocation = this.getSpawnLocation(); // Paper - Call SpawnChangeEvent; moved to nms.ServerLevel ++ this.world.setDefaultSpawnPos(new BlockPos(x, y, z), angle); // Paper - use ServerLevel#setDefaultSpawnPos + ++ // Paper start - Call SpawnChangeEvent; move to nms.ServerLevel + // Notify anyone who's listening. +- SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); +- this.server.getPluginManager().callEvent(event); ++ // SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); ++ // server.getPluginManager().callEvent(event); ++ // Paper end - Call SpawnChangeEvent + + return true; + } catch (Exception e) { diff --git a/patches/server/0389-Add-moon-phase-API.patch b/patches/server/0389-Add-moon-phase-API.patch new file mode 100644 index 0000000000..2fcd34c334 --- /dev/null +++ b/patches/server/0389-Add-moon-phase-API.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 23 Aug 2020 16:32:11 +0200 +Subject: [PATCH] Add moon phase API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +index 92a0c2049fa1df76cedfe7dfbd6e5fe402859f4b..15da29058f80a2d7cf2be26c48421c1746815a10 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +@@ -515,4 +515,11 @@ public abstract class CraftRegionAccessor implements RegionAccessor { + + throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName()); + } ++ ++ // Paper start ++ @Override ++ public io.papermc.paper.world.MoonPhase getMoonPhase() { ++ return io.papermc.paper.world.MoonPhase.getPhase(this.getHandle().dayTime() / 24000L); ++ } ++ // Paper end + } diff --git a/patches/server/0389-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch b/patches/server/0389-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch deleted file mode 100644 index 152014d89c..0000000000 --- a/patches/server/0389-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 22 Aug 2020 23:36:21 +0200 -Subject: [PATCH] Fix SpawnChangeEvent not firing for all use-cases - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index c631ea4e75798e36cc6418b1e71eeca89c8263d5..d32606cba7222aa538cca3882314f9f87f33684f 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1715,7 +1715,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - float f1 = this.levelData.getSpawnAngle(); - - if (!blockposition1.equals(pos) || f1 != angle) { -+ org.bukkit.Location prevSpawnLoc = this.getWorld().getSpawnLocation(); // Paper - Call SpawnChangeEvent - this.levelData.setSpawn(pos, angle); -+ new org.bukkit.event.world.SpawnChangeEvent(this.getWorld(), prevSpawnLoc).callEvent(); // Paper - Call SpawnChangeEvent - this.getServer().getPlayerList().broadcastAll(new ClientboundSetDefaultSpawnPositionPacket(pos, angle)); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 031c46e8cf1c49c4db2887dc32cbad75532f8faa..b877904bd18c96a4a7e49fb3e1aba2b6109f15cd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -243,12 +243,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - public boolean setSpawnLocation(int x, int y, int z, float angle) { - try { -- Location previousLocation = this.getSpawnLocation(); -- this.world.levelData.setSpawn(new BlockPos(x, y, z), angle); -+ // Location previousLocation = this.getSpawnLocation(); // Paper - Call SpawnChangeEvent; moved to nms.ServerLevel -+ this.world.setDefaultSpawnPos(new BlockPos(x, y, z), angle); // Paper - use ServerLevel#setDefaultSpawnPos - -+ // Paper start - Call SpawnChangeEvent; move to nms.ServerLevel - // Notify anyone who's listening. -- SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); -- this.server.getPluginManager().callEvent(event); -+ // SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); -+ // server.getPluginManager().callEvent(event); -+ // Paper end - Call SpawnChangeEvent - - return true; - } catch (Exception e) { diff --git a/patches/server/0390-Add-moon-phase-API.patch b/patches/server/0390-Add-moon-phase-API.patch deleted file mode 100644 index 2fcd34c334..0000000000 --- a/patches/server/0390-Add-moon-phase-API.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 23 Aug 2020 16:32:11 +0200 -Subject: [PATCH] Add moon phase API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -index 92a0c2049fa1df76cedfe7dfbd6e5fe402859f4b..15da29058f80a2d7cf2be26c48421c1746815a10 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -@@ -515,4 +515,11 @@ public abstract class CraftRegionAccessor implements RegionAccessor { - - throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName()); - } -+ -+ // Paper start -+ @Override -+ public io.papermc.paper.world.MoonPhase getMoonPhase() { -+ return io.papermc.paper.world.MoonPhase.getPhase(this.getHandle().dayTime() / 24000L); -+ } -+ // Paper end - } diff --git a/patches/server/0390-Do-not-let-the-server-load-chunks-from-newer-version.patch b/patches/server/0390-Do-not-let-the-server-load-chunks-from-newer-version.patch new file mode 100644 index 0000000000..3bdfea31f7 --- /dev/null +++ b/patches/server/0390-Do-not-let-the-server-load-chunks-from-newer-version.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Tue, 23 Jul 2019 20:44:47 -0500 +Subject: [PATCH] Do not let the server load chunks from newer versions + +If the server attempts to load a chunk generated by a newer version of +the game, immediately stop the server to prevent data corruption. + +You can override this functionality at your own peril. + +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 92ad7704a77c024afe090488764eaf59a4f7505f..d7a204216332ccbd6bece23bd507be0366ea4d61 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 +@@ -104,11 +104,25 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun + } + // Paper end - guard against serializing mismatching coordinates + ++ // Paper start - Do not let the server load chunks from newer versions ++ private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion(); ++ private static final boolean JUST_CORRUPT_IT = Boolean.getBoolean("Paper.ignoreWorldDataVersion"); ++ // Paper end - Do not let the server load chunks from newer versions ++ + @Nullable + public static SerializableChunkData parse(LevelHeightAccessor world, RegistryAccess registryManager, CompoundTag nbt) { + if (!nbt.contains("Status", 8)) { + return null; + } else { ++ // Paper start - Do not let the server load chunks from newer versions ++ if (nbt.contains("DataVersion", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { ++ final int dataVersion = nbt.getInt("DataVersion"); ++ if (!JUST_CORRUPT_IT && dataVersion > CURRENT_DATA_VERSION) { ++ new RuntimeException("Server attempted to load chunk saved with newer version of minecraft! " + dataVersion + " > " + CURRENT_DATA_VERSION).printStackTrace(); ++ System.exit(1); ++ } ++ } ++ // Paper end - Do not let the server load chunks from newer versions + ChunkPos chunkcoordintpair = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate + long i = nbt.getLong("LastUpdate"); + long j = nbt.getLong("InhabitedTime"); diff --git a/patches/server/0391-Do-not-let-the-server-load-chunks-from-newer-version.patch b/patches/server/0391-Do-not-let-the-server-load-chunks-from-newer-version.patch deleted file mode 100644 index 3bdfea31f7..0000000000 --- a/patches/server/0391-Do-not-let-the-server-load-chunks-from-newer-version.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Tue, 23 Jul 2019 20:44:47 -0500 -Subject: [PATCH] Do not let the server load chunks from newer versions - -If the server attempts to load a chunk generated by a newer version of -the game, immediately stop the server to prevent data corruption. - -You can override this functionality at your own peril. - -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 92ad7704a77c024afe090488764eaf59a4f7505f..d7a204216332ccbd6bece23bd507be0366ea4d61 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 -@@ -104,11 +104,25 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun - } - // Paper end - guard against serializing mismatching coordinates - -+ // Paper start - Do not let the server load chunks from newer versions -+ private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion(); -+ private static final boolean JUST_CORRUPT_IT = Boolean.getBoolean("Paper.ignoreWorldDataVersion"); -+ // Paper end - Do not let the server load chunks from newer versions -+ - @Nullable - public static SerializableChunkData parse(LevelHeightAccessor world, RegistryAccess registryManager, CompoundTag nbt) { - if (!nbt.contains("Status", 8)) { - return null; - } else { -+ // Paper start - Do not let the server load chunks from newer versions -+ if (nbt.contains("DataVersion", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { -+ final int dataVersion = nbt.getInt("DataVersion"); -+ if (!JUST_CORRUPT_IT && dataVersion > CURRENT_DATA_VERSION) { -+ new RuntimeException("Server attempted to load chunk saved with newer version of minecraft! " + dataVersion + " > " + CURRENT_DATA_VERSION).printStackTrace(); -+ System.exit(1); -+ } -+ } -+ // Paper end - Do not let the server load chunks from newer versions - ChunkPos chunkcoordintpair = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate - long i = nbt.getLong("LastUpdate"); - long j = nbt.getLong("InhabitedTime"); diff --git a/patches/server/0391-Prevent-headless-pistons-from-being-created.patch b/patches/server/0391-Prevent-headless-pistons-from-being-created.patch new file mode 100644 index 0000000000..788473f265 --- /dev/null +++ b/patches/server/0391-Prevent-headless-pistons-from-being-created.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: commandblockguy +Date: Fri, 14 Aug 2020 14:44:14 -0500 +Subject: [PATCH] Prevent headless pistons from being created + +Prevent headless pistons from being created by explosions or tree/mushroom growth. + +diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java +index 290fd9d57c5de2c92afe23babfcdc3d110a35b9e..dfb7cb134d1f9bce3d8d17fbf50d9b3309f76078 100644 +--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java ++++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java +@@ -164,6 +164,15 @@ public class ServerExplosion implements Explosion { + + if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockposition, iblockdata, f)) { + set.add(blockposition); ++ // Paper start - prevent headless pistons from forming ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == Blocks.MOVING_PISTON) { ++ net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(blockposition); ++ if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) { ++ net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING); ++ set.add(blockposition.relative(direction.getOpposite())); ++ } ++ } ++ // Paper end - prevent headless pistons from forming + } + + d4 += d0 * 0.30000001192092896D; diff --git a/patches/server/0392-Add-BellRingEvent.patch b/patches/server/0392-Add-BellRingEvent.patch new file mode 100644 index 0000000000..c78e88ccaa --- /dev/null +++ b/patches/server/0392-Add-BellRingEvent.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eearslya Sleiarion +Date: Sun, 23 Aug 2020 13:04:02 +0200 +Subject: [PATCH] Add BellRingEvent + +Add a new event, BellRingEvent, to trigger whenever a player rings a +village bell. Passes along the bell block and the player who rang it. + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index f8ec0bca1683d172bc673afc28cf9f7b76e26130..798a608784d4880f8d8e77960cfaf27700d06ddb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -377,10 +377,11 @@ public class CraftEventFactory { + return tradeSelectEvent; + } + ++ @SuppressWarnings("deprecation") // Paper use deprecated event to maintain compat (it extends modern event) + public static boolean handleBellRingEvent(Level world, BlockPos position, Direction direction, Entity entity) { + Block block = CraftBlock.at(world, position); + BlockFace bukkitDirection = CraftBlock.notchToBlockFace(direction); +- BellRingEvent event = new BellRingEvent(block, bukkitDirection, (entity != null) ? entity.getBukkitEntity() : null); ++ BellRingEvent event = new io.papermc.paper.event.block.BellRingEvent(block, bukkitDirection, (entity != null) ? entity.getBukkitEntity() : null); // Paper - deprecated BellRingEvent + Bukkit.getPluginManager().callEvent(event); + return !event.isCancelled(); + } diff --git a/patches/server/0392-Prevent-headless-pistons-from-being-created.patch b/patches/server/0392-Prevent-headless-pistons-from-being-created.patch deleted file mode 100644 index 788473f265..0000000000 --- a/patches/server/0392-Prevent-headless-pistons-from-being-created.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: commandblockguy -Date: Fri, 14 Aug 2020 14:44:14 -0500 -Subject: [PATCH] Prevent headless pistons from being created - -Prevent headless pistons from being created by explosions or tree/mushroom growth. - -diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java -index 290fd9d57c5de2c92afe23babfcdc3d110a35b9e..dfb7cb134d1f9bce3d8d17fbf50d9b3309f76078 100644 ---- a/src/main/java/net/minecraft/world/level/ServerExplosion.java -+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java -@@ -164,6 +164,15 @@ public class ServerExplosion implements Explosion { - - if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockposition, iblockdata, f)) { - set.add(blockposition); -+ // Paper start - prevent headless pistons from forming -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == Blocks.MOVING_PISTON) { -+ net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(blockposition); -+ if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) { -+ net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING); -+ set.add(blockposition.relative(direction.getOpposite())); -+ } -+ } -+ // Paper end - prevent headless pistons from forming - } - - d4 += d0 * 0.30000001192092896D; diff --git a/patches/server/0393-Add-BellRingEvent.patch b/patches/server/0393-Add-BellRingEvent.patch deleted file mode 100644 index c78e88ccaa..0000000000 --- a/patches/server/0393-Add-BellRingEvent.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eearslya Sleiarion -Date: Sun, 23 Aug 2020 13:04:02 +0200 -Subject: [PATCH] Add BellRingEvent - -Add a new event, BellRingEvent, to trigger whenever a player rings a -village bell. Passes along the bell block and the player who rang it. - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index f8ec0bca1683d172bc673afc28cf9f7b76e26130..798a608784d4880f8d8e77960cfaf27700d06ddb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -377,10 +377,11 @@ public class CraftEventFactory { - return tradeSelectEvent; - } - -+ @SuppressWarnings("deprecation") // Paper use deprecated event to maintain compat (it extends modern event) - public static boolean handleBellRingEvent(Level world, BlockPos position, Direction direction, Entity entity) { - Block block = CraftBlock.at(world, position); - BlockFace bukkitDirection = CraftBlock.notchToBlockFace(direction); -- BellRingEvent event = new BellRingEvent(block, bukkitDirection, (entity != null) ? entity.getBukkitEntity() : null); -+ BellRingEvent event = new io.papermc.paper.event.block.BellRingEvent(block, bukkitDirection, (entity != null) ? entity.getBukkitEntity() : null); // Paper - deprecated BellRingEvent - Bukkit.getPluginManager().callEvent(event); - return !event.isCancelled(); - } diff --git a/patches/server/0393-Add-zombie-targets-turtle-egg-config.patch b/patches/server/0393-Add-zombie-targets-turtle-egg-config.patch new file mode 100644 index 0000000000..73a1b707b4 --- /dev/null +++ b/patches/server/0393-Add-zombie-targets-turtle-egg-config.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 23 Aug 2020 15:47:34 +0200 +Subject: [PATCH] Add zombie targets turtle egg config + + +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 5b8ac7113eb8a57fe07bfaacc1b1320383a56d06..c182bdcc5da5652f8b34b4cb8d28651cf79009fe 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java +@@ -112,7 +112,7 @@ public class Zombie extends Monster { + + @Override + protected void registerGoals() { +- this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); ++ if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); // Paper - Add zombie targets turtle egg config + this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.addBehaviourGoals(); diff --git a/patches/server/0394-Add-zombie-targets-turtle-egg-config.patch b/patches/server/0394-Add-zombie-targets-turtle-egg-config.patch deleted file mode 100644 index 73a1b707b4..0000000000 --- a/patches/server/0394-Add-zombie-targets-turtle-egg-config.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 23 Aug 2020 15:47:34 +0200 -Subject: [PATCH] Add zombie targets turtle egg config - - -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 5b8ac7113eb8a57fe07bfaacc1b1320383a56d06..c182bdcc5da5652f8b34b4cb8d28651cf79009fe 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -112,7 +112,7 @@ public class Zombie extends Monster { - - @Override - protected void registerGoals() { -- this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); -+ if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); // Paper - Add zombie targets turtle egg config - this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); - this.addBehaviourGoals(); diff --git a/patches/server/0394-Buffer-joins-to-world.patch b/patches/server/0394-Buffer-joins-to-world.patch new file mode 100644 index 0000000000..217062d3c5 --- /dev/null +++ b/patches/server/0394-Buffer-joins-to-world.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Wed, 19 Aug 2020 05:05:54 +0100 +Subject: [PATCH] Buffer joins to world + +This patch buffers the number of logins which will attempt to join +the world per tick, this attempts to reduce the impact that join floods +has on the server + +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index e9429b3b1db612aa552237fe5d0c37727501ff8d..f9158826f16e45c81714c2e0a284828bc5bb95c8 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -445,12 +445,26 @@ public class Connection extends SimpleChannelInboundHandler> { + } + } + ++ private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world ++ private static int joinAttemptsThisTick; // Paper - Buffer joins to world ++ private static int currTick; // Paper - Buffer joins to world + public void tick() { + this.flushQueue(); ++ // Paper start - Buffer joins to world ++ if (Connection.currTick != net.minecraft.server.MinecraftServer.currentTick) { ++ Connection.currTick = net.minecraft.server.MinecraftServer.currentTick; ++ Connection.joinAttemptsThisTick = 0; ++ } ++ // Paper end - Buffer joins to world + PacketListener packetlistener = this.packetListener; + + if (packetlistener instanceof TickablePacketListener tickablepacketlistener) { ++ // Paper start - Buffer joins to world ++ if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) ++ || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING ++ || Connection.joinAttemptsThisTick++ < MAX_PER_TICK) { + tickablepacketlistener.tick(); ++ } // Paper end - Buffer joins to world + } + + if (!this.isConnected() && !this.disconnectionHandled) { diff --git a/patches/server/0395-Buffer-joins-to-world.patch b/patches/server/0395-Buffer-joins-to-world.patch deleted file mode 100644 index 217062d3c5..0000000000 --- a/patches/server/0395-Buffer-joins-to-world.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Wed, 19 Aug 2020 05:05:54 +0100 -Subject: [PATCH] Buffer joins to world - -This patch buffers the number of logins which will attempt to join -the world per tick, this attempts to reduce the impact that join floods -has on the server - -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index e9429b3b1db612aa552237fe5d0c37727501ff8d..f9158826f16e45c81714c2e0a284828bc5bb95c8 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -445,12 +445,26 @@ public class Connection extends SimpleChannelInboundHandler> { - } - } - -+ private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world -+ private static int joinAttemptsThisTick; // Paper - Buffer joins to world -+ private static int currTick; // Paper - Buffer joins to world - public void tick() { - this.flushQueue(); -+ // Paper start - Buffer joins to world -+ if (Connection.currTick != net.minecraft.server.MinecraftServer.currentTick) { -+ Connection.currTick = net.minecraft.server.MinecraftServer.currentTick; -+ Connection.joinAttemptsThisTick = 0; -+ } -+ // Paper end - Buffer joins to world - PacketListener packetlistener = this.packetListener; - - if (packetlistener instanceof TickablePacketListener tickablepacketlistener) { -+ // Paper start - Buffer joins to world -+ if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) -+ || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING -+ || Connection.joinAttemptsThisTick++ < MAX_PER_TICK) { - tickablepacketlistener.tick(); -+ } // Paper end - Buffer joins to world - } - - if (!this.isConnected() && !this.disconnectionHandled) { diff --git a/patches/server/0395-Fix-hex-colors-not-working-in-some-kick-messages.patch b/patches/server/0395-Fix-hex-colors-not-working-in-some-kick-messages.patch new file mode 100644 index 0000000000..1cafcc355b --- /dev/null +++ b/patches/server/0395-Fix-hex-colors-not-working-in-some-kick-messages.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Thu, 27 Aug 2020 16:57:25 -0400 +Subject: [PATCH] Fix hex colors not working in some kick messages + + +diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java +index 946b423d2184f903dc29c923d7dbe05aaa469c09..0c1bdf2329936ce479a2cc53e8a46bd2ad685ec1 100644 +--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java +@@ -113,14 +113,16 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL + } + // CraftBukkit end + if (packet.protocolVersion() != SharedConstants.getCurrentVersion().getProtocolVersion()) { +- MutableComponent ichatmutablecomponent; ++ net.kyori.adventure.text.Component adventureComponent; // Paper - Fix hex colors not working in some kick messages + + if (packet.protocolVersion() < SharedConstants.getCurrentVersion().getProtocolVersion()) { // Spigot - SPIGOT-7546: Handle version check correctly for outdated client message +- ichatmutablecomponent = Component.literal( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName() ) ); // Spigot ++ adventureComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(java.text.MessageFormat.format(org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName())); // Spigot // Paper - Fix hex colors not working in some kick messages + } else { +- ichatmutablecomponent = Component.literal( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName() ) ); // Spigot ++ adventureComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(java.text.MessageFormat.format(org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName())); // Spigot // Paper - Fix hex colors not working in some kick messages + } + ++ Component ichatmutablecomponent = io.papermc.paper.adventure.PaperAdventure.asVanilla(adventureComponent); // Paper - Fix hex colors not working in some kick messages ++ + this.connection.send(new ClientboundLoginDisconnectPacket(ichatmutablecomponent)); + this.connection.disconnect((Component) ichatmutablecomponent); + } else { +diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index fd9e6781a18d41ca3982788711749d11575566d0..9d5723cdfdbf6257a71e57842aea9ba317fc049a 100644 +--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +@@ -133,7 +133,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + // CraftBukkit start + @Deprecated + public void disconnect(String s) { +- this.disconnect(Component.literal(s)); ++ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(s))); // Paper - Fix hex colors not working in some kick messages + } + // CraftBukkit end + diff --git a/patches/server/0396-Add-more-Evoker-API.patch b/patches/server/0396-Add-more-Evoker-API.patch new file mode 100644 index 0000000000..f44eceff55 --- /dev/null +++ b/patches/server/0396-Add-more-Evoker-API.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 23 Aug 2020 15:28:35 +0200 +Subject: [PATCH] Add more Evoker API + +== AT == +public net.minecraft.world.entity.monster.Evoker setWololoTarget(Lnet/minecraft/world/entity/animal/Sheep;)V +public net.minecraft.world.entity.monster.Evoker getWololoTarget()Lnet/minecraft/world/entity/animal/Sheep; + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java +index 93ffe2ac37b03aa289881f5f12c7aa7f1d835eda..3a890cccf1766758794f3a3b5d31428f42590049 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java +@@ -1,5 +1,6 @@ + package org.bukkit.craftbukkit.entity; + ++import net.minecraft.world.entity.animal.Sheep; + import net.minecraft.world.entity.monster.SpellcasterIllager; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.entity.Evoker; +@@ -29,4 +30,17 @@ public class CraftEvoker extends CraftSpellcaster implements Evoker { + public void setCurrentSpell(Evoker.Spell spell) { + this.getHandle().setIsCastingSpell(spell == null ? SpellcasterIllager.IllagerSpell.NONE : SpellcasterIllager.IllagerSpell.byId(spell.ordinal())); + } ++ ++ // Paper start - Add more Evoker API ++ @Override ++ public org.bukkit.entity.Sheep getWololoTarget() { ++ Sheep sheep = getHandle().getWololoTarget(); ++ return sheep == null ? null : (org.bukkit.entity.Sheep) sheep.getBukkitEntity(); ++ } ++ ++ @Override ++ public void setWololoTarget(org.bukkit.entity.Sheep sheep) { ++ getHandle().setWololoTarget(sheep == null ? null : ((org.bukkit.craftbukkit.entity.CraftSheep) sheep).getHandle()); ++ } ++ // Paper end - Add more Evoker API + } diff --git a/patches/server/0396-Fix-hex-colors-not-working-in-some-kick-messages.patch b/patches/server/0396-Fix-hex-colors-not-working-in-some-kick-messages.patch deleted file mode 100644 index 1cafcc355b..0000000000 --- a/patches/server/0396-Fix-hex-colors-not-working-in-some-kick-messages.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Thu, 27 Aug 2020 16:57:25 -0400 -Subject: [PATCH] Fix hex colors not working in some kick messages - - -diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java -index 946b423d2184f903dc29c923d7dbe05aaa469c09..0c1bdf2329936ce479a2cc53e8a46bd2ad685ec1 100644 ---- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java -@@ -113,14 +113,16 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL - } - // CraftBukkit end - if (packet.protocolVersion() != SharedConstants.getCurrentVersion().getProtocolVersion()) { -- MutableComponent ichatmutablecomponent; -+ net.kyori.adventure.text.Component adventureComponent; // Paper - Fix hex colors not working in some kick messages - - if (packet.protocolVersion() < SharedConstants.getCurrentVersion().getProtocolVersion()) { // Spigot - SPIGOT-7546: Handle version check correctly for outdated client message -- ichatmutablecomponent = Component.literal( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName() ) ); // Spigot -+ adventureComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(java.text.MessageFormat.format(org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName())); // Spigot // Paper - Fix hex colors not working in some kick messages - } else { -- ichatmutablecomponent = Component.literal( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName() ) ); // Spigot -+ adventureComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(java.text.MessageFormat.format(org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().getName())); // Spigot // Paper - Fix hex colors not working in some kick messages - } - -+ Component ichatmutablecomponent = io.papermc.paper.adventure.PaperAdventure.asVanilla(adventureComponent); // Paper - Fix hex colors not working in some kick messages -+ - this.connection.send(new ClientboundLoginDisconnectPacket(ichatmutablecomponent)); - this.connection.disconnect((Component) ichatmutablecomponent); - } else { -diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index fd9e6781a18d41ca3982788711749d11575566d0..9d5723cdfdbf6257a71e57842aea9ba317fc049a 100644 ---- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -133,7 +133,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - // CraftBukkit start - @Deprecated - public void disconnect(String s) { -- this.disconnect(Component.literal(s)); -+ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(s))); // Paper - Fix hex colors not working in some kick messages - } - // CraftBukkit end - diff --git a/patches/server/0397-Add-methods-to-get-translation-keys.patch b/patches/server/0397-Add-methods-to-get-translation-keys.patch new file mode 100644 index 0000000000..667be15737 --- /dev/null +++ b/patches/server/0397-Add-methods-to-get-translation-keys.patch @@ -0,0 +1,227 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 11 Aug 2020 19:16:09 +0200 +Subject: [PATCH] Add methods to get translation keys + +== AT == +public org.bukkit.craftbukkit.inventory.CraftMetaFirework +public org.bukkit.craftbukkit.inventory.CraftMetaFirework power +public org.bukkit.craftbukkit.inventory.CraftMetaFirework getNBT(Lorg/bukkit/FireworkEffect$Type;)Lnet/minecraft/world/item/component/FireworkExplosion$Shape; + +Co-authored-by: MeFisto94 + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java +index fa0a3f895f12a33938222d354caf13857bdd6955..fb8f68f1aedfb26e4d95fe5bad87f0f2cc91c287 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java +@@ -68,6 +68,16 @@ public class CraftMusicInstrument extends MusicInstrument implements Handleable< + return this.key; + } + ++ // Paper start - add translationKey methods ++ @Override ++ public @NotNull String translationKey() { ++ if (!(this.getHandle().description().getContents() instanceof final net.minecraft.network.chat.contents.TranslatableContents translatableContents)) { ++ throw new UnsupportedOperationException("Description isn't translatable!"); // Paper ++ } ++ return translatableContents.getKey(); ++ } ++ // Paper end - add translationKey methods ++ + @Override + public boolean equals(Object other) { + if (this == other) { +diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java +index 8797a47be16b85dc69a28a56bb355bee7d6b1a78..9ab615347e241ac264fb70f43306075907420885 100644 +--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java +@@ -98,6 +98,11 @@ public class CraftAttribute implements Attribute, Handleable implements BlockType.Typed, + public Material asMaterial() { + return Registry.MATERIAL.get(this.key); + } ++ ++ // Paper start - add Translatable ++ @Override ++ public String translationKey() { ++ return this.block.getDescriptionId(); ++ } ++ // Paper end - add Translatable + } +diff --git a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java +index f73017bff613bd62b86c974b29576e241c24c927..59c9c970b83f62245d860994c4ac0c21dcc15398 100644 +--- a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java ++++ b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java +@@ -152,6 +152,17 @@ public class CraftEnchantment extends Enchantment implements Handleable implements ItemType.Typed, Han + public Material asMaterial() { + return Registry.MATERIAL.get(this.key); + } ++ ++ // Paper start - add Translatable ++ @Override ++ public String translationKey() { ++ return this.item.getDescriptionId(); ++ } ++ // Paper end - add Translatable + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java +index 4921fc085c9d60c74028ef390325e26c598e8df1..4941e0afff8df5f10f06c715b54bf58eb86051c5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java +@@ -123,7 +123,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + return new FireworkExplosion(CraftMetaFirework.getNBT(effect.getType()), colors, fadeColors, effect.hasTrail(), effect.hasFlicker()); + } + +- static FireworkExplosion.Shape getNBT(Type type) { ++ public static FireworkExplosion.Shape getNBT(Type type) { // Paper - package-private -> public + switch (type) { + case BALL: + return FireworkExplosion.Shape.SMALL_BALL; +diff --git a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java +index 01e0936ea8ce5bcacafd9e89a1c0dfd2c172024d..95b7506c1317f2664f52c88295aee1006db4da63 100644 +--- a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java ++++ b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java +@@ -1,11 +1,29 @@ + package io.papermc.paper.world; + + import com.destroystokyo.paper.ClientOption; ++import java.util.Locale; ++import java.util.Map; ++import net.minecraft.network.chat.contents.TranslatableContents; ++import net.minecraft.resources.ResourceKey; + import net.minecraft.server.level.ParticleStatus; + import net.minecraft.world.entity.player.ChatVisiblity; ++import net.minecraft.world.flag.FeatureFlags; ++import net.minecraft.world.level.GameRules; ++import net.minecraft.world.level.GameType; ++import net.minecraft.world.level.biome.Biome; ++import org.bukkit.Difficulty; ++import org.bukkit.FireworkEffect; ++import org.bukkit.GameMode; ++import org.bukkit.GameRule; ++import org.bukkit.attribute.Attribute; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.support.RegistryHelper; ++import org.bukkit.support.environment.AllFeatures; + import org.junit.jupiter.api.Assertions; ++import org.junit.jupiter.api.Disabled; + import org.junit.jupiter.api.Test; + ++@AllFeatures + public class TranslationKeyTest { + + @Test +@@ -22,4 +40,61 @@ public class TranslationKeyTest { + Assertions.assertEquals(ParticleStatus.valueOf(particleVisibility.name()).getKey(), particleVisibility.translationKey(), particleVisibility + "'s translation key doesn't match"); + } + } ++ ++ @Test ++ public void testDifficultyKeys() { ++ for (Difficulty bukkitDifficulty : Difficulty.values()) { ++ Assertions.assertEquals(((TranslatableContents) net.minecraft.world.Difficulty.byId(bukkitDifficulty.ordinal()).getDisplayName().getContents()).getKey(), bukkitDifficulty.translationKey(), bukkitDifficulty + "'s translation key doesn't match"); ++ } ++ } ++ ++ @Test ++ public void testGameruleKeys() { ++ final Map> gameRules = CraftWorld.getGameRulesNMS(new GameRules(FeatureFlags.REGISTRY.allFlags())); ++ for (GameRule rule : GameRule.values()) { ++ Assertions.assertEquals(gameRules.get(rule.getName()).getDescriptionId(), rule.translationKey(), rule.getName() + "'s translation doesn't match"); ++ } ++ } ++ ++ @Test ++ public void testAttributeKeys() { ++ for (Attribute attribute : Attribute.values()) { ++ Assertions.assertEquals(org.bukkit.craftbukkit.attribute.CraftAttribute.bukkitToMinecraft(attribute).getDescriptionId(), attribute.translationKey(), "translation key mismatch for " + attribute); ++ } ++ } ++ ++ @Test ++ public void testFireworkEffectType() { ++ for (final FireworkEffect.Type type : FireworkEffect.Type.values()) { ++ final net.minecraft.world.item.component.FireworkExplosion.Shape nmsType = org.bukkit.craftbukkit.inventory.CraftMetaFirework.getNBT(type); ++ Assertions.assertTrue(nmsType.getName().getContents() instanceof TranslatableContents, "contents aren't translatable"); ++ Assertions.assertEquals(((TranslatableContents) nmsType.getName().getContents()).getKey(), type.translationKey(), "translation key mismatch for " + type); ++ } ++ } ++ ++ @Test ++ @Disabled // TODO fix ++ public void testCreativeCategory() { ++ // for (CreativeModeTab tab : CreativeModeTabs.tabs()) { ++ // CreativeCategory category = Objects.requireNonNull(CraftCreativeCategory.fromNMS(tab)); ++ // Assertions.assertEquals("translation key mismatch for " + category, ((TranslatableContents) tab.getDisplayName().getContents()).getKey(), category.translationKey()); ++ // } ++ } ++ ++ @Test ++ public void testGameMode() { ++ for (GameType nms : GameType.values()) { ++ GameMode bukkit = GameMode.getByValue(nms.getId()); ++ Assertions.assertNotNull(bukkit); ++ Assertions.assertEquals(((TranslatableContents) nms.getLongDisplayName().getContents()).getKey(), bukkit.translationKey(), "translation key mismatch for " + bukkit); ++ } ++ } ++ ++ @Test ++ public void testBiome() { ++ for (Map.Entry, Biome> nms : RegistryHelper.getBiomes().entrySet()) { ++ org.bukkit.block.Biome bukkit = org.bukkit.block.Biome.valueOf(nms.getKey().location().getPath().toUpperCase(Locale.ROOT)); ++ Assertions.assertEquals(nms.getKey().location().toLanguageKey("biome"), bukkit.translationKey(), "translation key mismatch for " + bukkit); ++ } ++ } + } diff --git a/patches/server/0397-Add-more-Evoker-API.patch b/patches/server/0397-Add-more-Evoker-API.patch deleted file mode 100644 index f44eceff55..0000000000 --- a/patches/server/0397-Add-more-Evoker-API.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 23 Aug 2020 15:28:35 +0200 -Subject: [PATCH] Add more Evoker API - -== AT == -public net.minecraft.world.entity.monster.Evoker setWololoTarget(Lnet/minecraft/world/entity/animal/Sheep;)V -public net.minecraft.world.entity.monster.Evoker getWololoTarget()Lnet/minecraft/world/entity/animal/Sheep; - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java -index 93ffe2ac37b03aa289881f5f12c7aa7f1d835eda..3a890cccf1766758794f3a3b5d31428f42590049 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEvoker.java -@@ -1,5 +1,6 @@ - package org.bukkit.craftbukkit.entity; - -+import net.minecraft.world.entity.animal.Sheep; - import net.minecraft.world.entity.monster.SpellcasterIllager; - import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.entity.Evoker; -@@ -29,4 +30,17 @@ public class CraftEvoker extends CraftSpellcaster implements Evoker { - public void setCurrentSpell(Evoker.Spell spell) { - this.getHandle().setIsCastingSpell(spell == null ? SpellcasterIllager.IllagerSpell.NONE : SpellcasterIllager.IllagerSpell.byId(spell.ordinal())); - } -+ -+ // Paper start - Add more Evoker API -+ @Override -+ public org.bukkit.entity.Sheep getWololoTarget() { -+ Sheep sheep = getHandle().getWololoTarget(); -+ return sheep == null ? null : (org.bukkit.entity.Sheep) sheep.getBukkitEntity(); -+ } -+ -+ @Override -+ public void setWololoTarget(org.bukkit.entity.Sheep sheep) { -+ getHandle().setWololoTarget(sheep == null ? null : ((org.bukkit.craftbukkit.entity.CraftSheep) sheep).getHandle()); -+ } -+ // Paper end - Add more Evoker API - } diff --git a/patches/server/0398-Add-methods-to-get-translation-keys.patch b/patches/server/0398-Add-methods-to-get-translation-keys.patch deleted file mode 100644 index 667be15737..0000000000 --- a/patches/server/0398-Add-methods-to-get-translation-keys.patch +++ /dev/null @@ -1,227 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 11 Aug 2020 19:16:09 +0200 -Subject: [PATCH] Add methods to get translation keys - -== AT == -public org.bukkit.craftbukkit.inventory.CraftMetaFirework -public org.bukkit.craftbukkit.inventory.CraftMetaFirework power -public org.bukkit.craftbukkit.inventory.CraftMetaFirework getNBT(Lorg/bukkit/FireworkEffect$Type;)Lnet/minecraft/world/item/component/FireworkExplosion$Shape; - -Co-authored-by: MeFisto94 - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java -index fa0a3f895f12a33938222d354caf13857bdd6955..fb8f68f1aedfb26e4d95fe5bad87f0f2cc91c287 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java -@@ -68,6 +68,16 @@ public class CraftMusicInstrument extends MusicInstrument implements Handleable< - return this.key; - } - -+ // Paper start - add translationKey methods -+ @Override -+ public @NotNull String translationKey() { -+ if (!(this.getHandle().description().getContents() instanceof final net.minecraft.network.chat.contents.TranslatableContents translatableContents)) { -+ throw new UnsupportedOperationException("Description isn't translatable!"); // Paper -+ } -+ return translatableContents.getKey(); -+ } -+ // Paper end - add translationKey methods -+ - @Override - public boolean equals(Object other) { - if (this == other) { -diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java -index 8797a47be16b85dc69a28a56bb355bee7d6b1a78..9ab615347e241ac264fb70f43306075907420885 100644 ---- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java -@@ -98,6 +98,11 @@ public class CraftAttribute implements Attribute, Handleable implements BlockType.Typed, - public Material asMaterial() { - return Registry.MATERIAL.get(this.key); - } -+ -+ // Paper start - add Translatable -+ @Override -+ public String translationKey() { -+ return this.block.getDescriptionId(); -+ } -+ // Paper end - add Translatable - } -diff --git a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java -index f73017bff613bd62b86c974b29576e241c24c927..59c9c970b83f62245d860994c4ac0c21dcc15398 100644 ---- a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java -+++ b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java -@@ -152,6 +152,17 @@ public class CraftEnchantment extends Enchantment implements Handleable implements ItemType.Typed, Han - public Material asMaterial() { - return Registry.MATERIAL.get(this.key); - } -+ -+ // Paper start - add Translatable -+ @Override -+ public String translationKey() { -+ return this.item.getDescriptionId(); -+ } -+ // Paper end - add Translatable - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -index 4921fc085c9d60c74028ef390325e26c598e8df1..4941e0afff8df5f10f06c715b54bf58eb86051c5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -@@ -123,7 +123,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - return new FireworkExplosion(CraftMetaFirework.getNBT(effect.getType()), colors, fadeColors, effect.hasTrail(), effect.hasFlicker()); - } - -- static FireworkExplosion.Shape getNBT(Type type) { -+ public static FireworkExplosion.Shape getNBT(Type type) { // Paper - package-private -> public - switch (type) { - case BALL: - return FireworkExplosion.Shape.SMALL_BALL; -diff --git a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java -index 01e0936ea8ce5bcacafd9e89a1c0dfd2c172024d..95b7506c1317f2664f52c88295aee1006db4da63 100644 ---- a/src/test/java/io/papermc/paper/world/TranslationKeyTest.java -+++ b/src/test/java/io/papermc/paper/world/TranslationKeyTest.java -@@ -1,11 +1,29 @@ - package io.papermc.paper.world; - - import com.destroystokyo.paper.ClientOption; -+import java.util.Locale; -+import java.util.Map; -+import net.minecraft.network.chat.contents.TranslatableContents; -+import net.minecraft.resources.ResourceKey; - import net.minecraft.server.level.ParticleStatus; - import net.minecraft.world.entity.player.ChatVisiblity; -+import net.minecraft.world.flag.FeatureFlags; -+import net.minecraft.world.level.GameRules; -+import net.minecraft.world.level.GameType; -+import net.minecraft.world.level.biome.Biome; -+import org.bukkit.Difficulty; -+import org.bukkit.FireworkEffect; -+import org.bukkit.GameMode; -+import org.bukkit.GameRule; -+import org.bukkit.attribute.Attribute; -+import org.bukkit.craftbukkit.CraftWorld; -+import org.bukkit.support.RegistryHelper; -+import org.bukkit.support.environment.AllFeatures; - import org.junit.jupiter.api.Assertions; -+import org.junit.jupiter.api.Disabled; - import org.junit.jupiter.api.Test; - -+@AllFeatures - public class TranslationKeyTest { - - @Test -@@ -22,4 +40,61 @@ public class TranslationKeyTest { - Assertions.assertEquals(ParticleStatus.valueOf(particleVisibility.name()).getKey(), particleVisibility.translationKey(), particleVisibility + "'s translation key doesn't match"); - } - } -+ -+ @Test -+ public void testDifficultyKeys() { -+ for (Difficulty bukkitDifficulty : Difficulty.values()) { -+ Assertions.assertEquals(((TranslatableContents) net.minecraft.world.Difficulty.byId(bukkitDifficulty.ordinal()).getDisplayName().getContents()).getKey(), bukkitDifficulty.translationKey(), bukkitDifficulty + "'s translation key doesn't match"); -+ } -+ } -+ -+ @Test -+ public void testGameruleKeys() { -+ final Map> gameRules = CraftWorld.getGameRulesNMS(new GameRules(FeatureFlags.REGISTRY.allFlags())); -+ for (GameRule rule : GameRule.values()) { -+ Assertions.assertEquals(gameRules.get(rule.getName()).getDescriptionId(), rule.translationKey(), rule.getName() + "'s translation doesn't match"); -+ } -+ } -+ -+ @Test -+ public void testAttributeKeys() { -+ for (Attribute attribute : Attribute.values()) { -+ Assertions.assertEquals(org.bukkit.craftbukkit.attribute.CraftAttribute.bukkitToMinecraft(attribute).getDescriptionId(), attribute.translationKey(), "translation key mismatch for " + attribute); -+ } -+ } -+ -+ @Test -+ public void testFireworkEffectType() { -+ for (final FireworkEffect.Type type : FireworkEffect.Type.values()) { -+ final net.minecraft.world.item.component.FireworkExplosion.Shape nmsType = org.bukkit.craftbukkit.inventory.CraftMetaFirework.getNBT(type); -+ Assertions.assertTrue(nmsType.getName().getContents() instanceof TranslatableContents, "contents aren't translatable"); -+ Assertions.assertEquals(((TranslatableContents) nmsType.getName().getContents()).getKey(), type.translationKey(), "translation key mismatch for " + type); -+ } -+ } -+ -+ @Test -+ @Disabled // TODO fix -+ public void testCreativeCategory() { -+ // for (CreativeModeTab tab : CreativeModeTabs.tabs()) { -+ // CreativeCategory category = Objects.requireNonNull(CraftCreativeCategory.fromNMS(tab)); -+ // Assertions.assertEquals("translation key mismatch for " + category, ((TranslatableContents) tab.getDisplayName().getContents()).getKey(), category.translationKey()); -+ // } -+ } -+ -+ @Test -+ public void testGameMode() { -+ for (GameType nms : GameType.values()) { -+ GameMode bukkit = GameMode.getByValue(nms.getId()); -+ Assertions.assertNotNull(bukkit); -+ Assertions.assertEquals(((TranslatableContents) nms.getLongDisplayName().getContents()).getKey(), bukkit.translationKey(), "translation key mismatch for " + bukkit); -+ } -+ } -+ -+ @Test -+ public void testBiome() { -+ for (Map.Entry, Biome> nms : RegistryHelper.getBiomes().entrySet()) { -+ org.bukkit.block.Biome bukkit = org.bukkit.block.Biome.valueOf(nms.getKey().location().getPath().toUpperCase(Locale.ROOT)); -+ Assertions.assertEquals(nms.getKey().location().toLanguageKey("biome"), bukkit.translationKey(), "translation key mismatch for " + bukkit); -+ } -+ } - } diff --git a/patches/server/0398-Create-HoverEvent-from-ItemStack-Entity.patch b/patches/server/0398-Create-HoverEvent-from-ItemStack-Entity.patch new file mode 100644 index 0000000000..d487492e0c --- /dev/null +++ b/patches/server/0398-Create-HoverEvent-from-ItemStack-Entity.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: ysl3000 +Date: Mon, 6 Jul 2020 22:18:04 +0200 +Subject: [PATCH] Create HoverEvent from ItemStack Entity + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +index 77150a80d3523a923e2c9ccadda4887d6d960799..68798c90f2a116d82f6f25e920c54c929df6fca9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +@@ -251,4 +251,44 @@ public final class CraftItemFactory implements ItemFactory { + return nms != null ? nms.getItem().getName(nms).getString() : null; + } + // Paper end - add getI18NDisplayName ++ ++ // Paper start - bungee hover events ++ @Override ++ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(ItemStack itemStack) { ++ throw new UnsupportedOperationException("BungeeCord Chat API does not support data components"); ++ /* ++ net.md_5.bungee.api.chat.ItemTag itemTag = net.md_5.bungee.api.chat.ItemTag.ofNbt(CraftItemStack.asNMSCopy(itemStack).getOrCreateTag().toString()); ++ return new net.md_5.bungee.api.chat.hover.content.Item( ++ itemStack.getType().getKey().toString(), ++ itemStack.getAmount(), ++ itemTag); ++ */ ++ } ++ ++ @Override ++ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity) { ++ return hoverContentOf(entity, org.apache.commons.lang3.StringUtils.isBlank(entity.getCustomName()) ? null : new net.md_5.bungee.api.chat.TextComponent(entity.getCustomName())); ++ } ++ ++ @Override ++ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity, String customName) { ++ return hoverContentOf(entity, org.apache.commons.lang3.StringUtils.isBlank(customName) ? null : new net.md_5.bungee.api.chat.TextComponent(customName)); ++ } ++ ++ @Override ++ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity, net.md_5.bungee.api.chat.BaseComponent customName) { ++ return new net.md_5.bungee.api.chat.hover.content.Entity( ++ entity.getType().getKey().toString(), ++ entity.getUniqueId().toString(), ++ customName); ++ } ++ ++ @Override ++ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity, net.md_5.bungee.api.chat.BaseComponent[] customName) { ++ return new net.md_5.bungee.api.chat.hover.content.Entity( ++ entity.getType().getKey().toString(), ++ entity.getUniqueId().toString(), ++ new net.md_5.bungee.api.chat.TextComponent(customName)); ++ } ++ // Paper end - bungee hover events + } diff --git a/patches/server/0399-Cache-block-data-strings.patch b/patches/server/0399-Cache-block-data-strings.patch new file mode 100644 index 0000000000..89a3e25bc6 --- /dev/null +++ b/patches/server/0399-Cache-block-data-strings.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: miclebrick +Date: Thu, 6 Dec 2018 19:52:50 -0500 +Subject: [PATCH] Cache block data strings + + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 83848e30eeff52ccad591deb0d9e3a8ba1a122ed..6292256864aa0a265a73c0ef2af642d4ab387ccc 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -2184,6 +2184,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop>, Enum[]> ENUM_VALUES = new HashMap<>(); ++ private static final Map>, Enum[]> ENUM_VALUES = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - cache block data strings; make thread safe + + /** + * Convert an NMS Enum (usually a BlockStateEnum) to its appropriate Bukkit +@@ -548,7 +548,38 @@ public class CraftBlockData implements BlockData { + Preconditions.checkState(CraftBlockData.MAP.put(nms, bukkit) == null, "Duplicate mapping %s->%s", nms, bukkit); + } + ++ // Paper start - cache block data strings ++ private static Map stringDataCache = new java.util.concurrent.ConcurrentHashMap<>(); ++ ++ static { ++ // cache all of the default states at startup, will not cache ones with the custom states inside of the ++ // brackets in a different order, though ++ reloadCache(); ++ } ++ ++ public static void reloadCache() { ++ stringDataCache.clear(); ++ Block.BLOCK_STATE_REGISTRY.forEach(blockData -> stringDataCache.put(blockData.toString(), blockData.createCraftBlockData())); ++ } ++ // Paper end - cache block data strings ++ + public static CraftBlockData newData(BlockType blockType, String data) { ++ ++ // Paper start - cache block data strings ++ if (blockType != null) { ++ Block block = CraftBlockType.bukkitToMinecraftNew(blockType); ++ if (block != null) { ++ net.minecraft.resources.ResourceLocation key = BuiltInRegistries.BLOCK.getKey(block); ++ data = data == null ? key.toString() : key + data; ++ } ++ } ++ ++ CraftBlockData cached = stringDataCache.computeIfAbsent(data, s -> createNewData(null, s)); ++ return (CraftBlockData) cached.clone(); ++ } ++ ++ private static CraftBlockData createNewData(BlockType blockType, String data) { ++ // Paper end - cache block data strings + net.minecraft.world.level.block.state.BlockState blockData; + Block block = blockType == null ? null : ((CraftBlockType) blockType).getHandle(); + Map, Comparable> parsed = null; diff --git a/patches/server/0399-Create-HoverEvent-from-ItemStack-Entity.patch b/patches/server/0399-Create-HoverEvent-from-ItemStack-Entity.patch deleted file mode 100644 index d487492e0c..0000000000 --- a/patches/server/0399-Create-HoverEvent-from-ItemStack-Entity.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: ysl3000 -Date: Mon, 6 Jul 2020 22:18:04 +0200 -Subject: [PATCH] Create HoverEvent from ItemStack Entity - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -index 77150a80d3523a923e2c9ccadda4887d6d960799..68798c90f2a116d82f6f25e920c54c929df6fca9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -@@ -251,4 +251,44 @@ public final class CraftItemFactory implements ItemFactory { - return nms != null ? nms.getItem().getName(nms).getString() : null; - } - // Paper end - add getI18NDisplayName -+ -+ // Paper start - bungee hover events -+ @Override -+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(ItemStack itemStack) { -+ throw new UnsupportedOperationException("BungeeCord Chat API does not support data components"); -+ /* -+ net.md_5.bungee.api.chat.ItemTag itemTag = net.md_5.bungee.api.chat.ItemTag.ofNbt(CraftItemStack.asNMSCopy(itemStack).getOrCreateTag().toString()); -+ return new net.md_5.bungee.api.chat.hover.content.Item( -+ itemStack.getType().getKey().toString(), -+ itemStack.getAmount(), -+ itemTag); -+ */ -+ } -+ -+ @Override -+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity) { -+ return hoverContentOf(entity, org.apache.commons.lang3.StringUtils.isBlank(entity.getCustomName()) ? null : new net.md_5.bungee.api.chat.TextComponent(entity.getCustomName())); -+ } -+ -+ @Override -+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity, String customName) { -+ return hoverContentOf(entity, org.apache.commons.lang3.StringUtils.isBlank(customName) ? null : new net.md_5.bungee.api.chat.TextComponent(customName)); -+ } -+ -+ @Override -+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity, net.md_5.bungee.api.chat.BaseComponent customName) { -+ return new net.md_5.bungee.api.chat.hover.content.Entity( -+ entity.getType().getKey().toString(), -+ entity.getUniqueId().toString(), -+ customName); -+ } -+ -+ @Override -+ public net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(org.bukkit.entity.Entity entity, net.md_5.bungee.api.chat.BaseComponent[] customName) { -+ return new net.md_5.bungee.api.chat.hover.content.Entity( -+ entity.getType().getKey().toString(), -+ entity.getUniqueId().toString(), -+ new net.md_5.bungee.api.chat.TextComponent(customName)); -+ } -+ // Paper end - bungee hover events - } diff --git a/patches/server/0400-Cache-block-data-strings.patch b/patches/server/0400-Cache-block-data-strings.patch deleted file mode 100644 index 89a3e25bc6..0000000000 --- a/patches/server/0400-Cache-block-data-strings.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: miclebrick -Date: Thu, 6 Dec 2018 19:52:50 -0500 -Subject: [PATCH] Cache block data strings - - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 83848e30eeff52ccad591deb0d9e3a8ba1a122ed..6292256864aa0a265a73c0ef2af642d4ab387ccc 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2184,6 +2184,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop>, Enum[]> ENUM_VALUES = new HashMap<>(); -+ private static final Map>, Enum[]> ENUM_VALUES = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - cache block data strings; make thread safe - - /** - * Convert an NMS Enum (usually a BlockStateEnum) to its appropriate Bukkit -@@ -548,7 +548,38 @@ public class CraftBlockData implements BlockData { - Preconditions.checkState(CraftBlockData.MAP.put(nms, bukkit) == null, "Duplicate mapping %s->%s", nms, bukkit); - } - -+ // Paper start - cache block data strings -+ private static Map stringDataCache = new java.util.concurrent.ConcurrentHashMap<>(); -+ -+ static { -+ // cache all of the default states at startup, will not cache ones with the custom states inside of the -+ // brackets in a different order, though -+ reloadCache(); -+ } -+ -+ public static void reloadCache() { -+ stringDataCache.clear(); -+ Block.BLOCK_STATE_REGISTRY.forEach(blockData -> stringDataCache.put(blockData.toString(), blockData.createCraftBlockData())); -+ } -+ // Paper end - cache block data strings -+ - public static CraftBlockData newData(BlockType blockType, String data) { -+ -+ // Paper start - cache block data strings -+ if (blockType != null) { -+ Block block = CraftBlockType.bukkitToMinecraftNew(blockType); -+ if (block != null) { -+ net.minecraft.resources.ResourceLocation key = BuiltInRegistries.BLOCK.getKey(block); -+ data = data == null ? key.toString() : key + data; -+ } -+ } -+ -+ CraftBlockData cached = stringDataCache.computeIfAbsent(data, s -> createNewData(null, s)); -+ return (CraftBlockData) cached.clone(); -+ } -+ -+ private static CraftBlockData createNewData(BlockType blockType, String data) { -+ // Paper end - cache block data strings - net.minecraft.world.level.block.state.BlockState blockData; - Block block = blockType == null ? null : ((CraftBlockType) blockType).getHandle(); - Map, Comparable> parsed = null; diff --git a/patches/server/0400-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch b/patches/server/0400-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch new file mode 100644 index 0000000000..a3a03437b2 --- /dev/null +++ b/patches/server/0400-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 25 Aug 2020 20:45:36 -0400 +Subject: [PATCH] Fix Entity Teleportation and cancel velocity if teleported + +Uses correct setPositionRotation for Entity teleporting instead of setLocation +as this is how Vanilla teleports entities. + +Cancel any pending motion when teleported. + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index eab19d5ac362c4779e91fad0ede3e4c26f29ab01..0d7dae5fa79cd302d73d1be51d8bf908a816c4ca 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -680,7 +680,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + return; + } + +- this.player.absMoveTo(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); ++ this.player.moveTo(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); // Paper - Fix Entity Teleportation and cancel velocity if teleported + this.lastGoodX = this.awaitingPositionFromClient.x; + this.lastGoodY = this.awaitingPositionFromClient.y; + this.lastGoodZ = this.awaitingPositionFromClient.z; +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index abcdb8d082dd0bbcd60c1d0d924b6774dd196ea7..d871b45ea22f1f2019ca1d1e0708d8861daec633 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -180,6 +180,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + + // CraftBukkit start + private static final int CURRENT_LEVEL = 2; ++ public boolean preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; keep initial motion on first setPositionRotation + static boolean isLevelAtLeast(CompoundTag tag, int level) { + return tag.contains("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level; + } +@@ -1967,6 +1968,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public void moveTo(double x, double y, double z, float yaw, float pitch) { ++ // Paper start - Fix Entity Teleportation and cancel velocity if teleported ++ if (!preserveMotion) { ++ this.deltaMovement = Vec3.ZERO; ++ } else { ++ this.preserveMotion = false; ++ } ++ // Paper end - Fix Entity Teleportation and cancel velocity if teleported + this.setPosRaw(x, y, z); + this.setYRot(yaw); + this.setXRot(pitch); +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java +index 2db75673e525708d04bda9f6c9af80e7f8d361e6..be2b5f56f6f29c82c4fa9df33287d0ddb589f383 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java +@@ -79,6 +79,7 @@ public class DragonStrafePlayerPhase extends AbstractDragonPhaseInstance { + } + + DragonFireball dragonFireball = new DragonFireball(world, this.dragon, vec34.normalize()); ++ dragonFireball.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported + dragonFireball.moveTo(o, p, q, 0.0F, 0.0F); + if (new com.destroystokyo.paper.event.entity.EnderDragonShootFireballEvent((org.bukkit.entity.EnderDragon) dragon.getBukkitEntity(), (org.bukkit.entity.DragonFireball) dragonFireball.getBukkitEntity()).callEvent()) // Paper - EnderDragon Events + world.addFreshEntity(dragonFireball); +diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java +index 56dbe701a93eb9f1309bec92e5d3b310860a4dc5..1b6ec72f59504d2f420d6d5dcbed4d3b9115e3d8 100644 +--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java ++++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java +@@ -164,6 +164,7 @@ public abstract class BaseSpawner { + return; + } + ++ entity.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; preserve entity motion from tag + entity.moveTo(entity.getX(), entity.getY(), entity.getZ(), randomsource.nextFloat() * 360.0F, 0.0F); + if (entity instanceof Mob) { + Mob entityinsentient = (Mob) entity; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index ec122fa4e443290ff973797740172e07f8e736ca..609c768ba4d22e346acbc9422ce41e3b887fadb1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -241,7 +241,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + } + + // entity.setLocation() throws no event, and so cannot be cancelled +- this.entity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); ++ entity.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); // Paper - use proper moveTo, as per vanilla teleporting + // SPIGOT-619: Force sync head rotation also + this.entity.setYHeadRot(location.getYaw()); + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 0aa3fd9dce0cf90b1f74551c864e9ebf326eb1f3..e979681142bd08aeb00a98b79789a8f41b2a37af 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -603,6 +603,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + } + + ((AbstractHurtingProjectile) launch).projectileSource = this; ++ launch.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported + launch.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } else if (LlamaSpit.class.isAssignableFrom(projectile)) { + Location location = this.getEyeLocation(); diff --git a/patches/server/0401-Add-additional-open-container-api-to-HumanEntity.patch b/patches/server/0401-Add-additional-open-container-api-to-HumanEntity.patch new file mode 100644 index 0000000000..4f9cf8d9d9 --- /dev/null +++ b/patches/server/0401-Add-additional-open-container-api-to-HumanEntity.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Wed, 26 Aug 2020 02:12:31 -0400 +Subject: [PATCH] Add additional open container api to HumanEntity + +== AT == +public net/minecraft/world/level/block/state/BlockBehaviour getMenuProvider(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/MenuProvider; + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +index b2ab430392fc0f214ba8c5383e3f3ad5c548bda2..9022555db0df8c269fc039c895422cf36c08097e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -471,6 +471,70 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + return this.getHandle().containerMenu.getBukkitView(); + } + ++ // Paper start - Add additional containers ++ @Override ++ public InventoryView openAnvil(Location location, boolean force) { ++ return this.openInventory(location, force, Material.ANVIL); ++ } ++ ++ @Override ++ public InventoryView openCartographyTable(Location location, boolean force) { ++ return this.openInventory(location, force, Material.CARTOGRAPHY_TABLE); ++ } ++ ++ @Override ++ public InventoryView openGrindstone(Location location, boolean force) { ++ return this.openInventory(location, force, Material.GRINDSTONE); ++ } ++ ++ @Override ++ public InventoryView openLoom(Location location, boolean force) { ++ return this.openInventory(location, force, Material.LOOM); ++ } ++ ++ @Override ++ public InventoryView openSmithingTable(Location location, boolean force) { ++ return this.openInventory(location, force, Material.SMITHING_TABLE); ++ } ++ ++ @Override ++ public InventoryView openStonecutter(Location location, boolean force) { ++ return this.openInventory(location, force, Material.STONECUTTER); ++ } ++ ++ private InventoryView openInventory(Location location, boolean force, Material material) { ++ org.spigotmc.AsyncCatcher.catchOp("open" + material); ++ if (location == null) { ++ location = this.getLocation(); ++ } ++ if (!force) { ++ Block block = location.getBlock(); ++ if (block.getType() != material) { ++ return null; ++ } ++ } ++ net.minecraft.world.level.block.Block block; ++ if (material == Material.ANVIL) { ++ block = Blocks.ANVIL; ++ } else if (material == Material.CARTOGRAPHY_TABLE) { ++ block = Blocks.CARTOGRAPHY_TABLE; ++ } else if (material == Material.GRINDSTONE) { ++ block = Blocks.GRINDSTONE; ++ } else if (material == Material.LOOM) { ++ block = Blocks.LOOM; ++ } else if (material == Material.SMITHING_TABLE) { ++ block = Blocks.SMITHING_TABLE; ++ } else if (material == Material.STONECUTTER) { ++ block = Blocks.STONECUTTER; ++ } else { ++ throw new IllegalArgumentException("Unsupported inventory type: " + material); ++ } ++ this.getHandle().openMenu(block.getMenuProvider(null, this.getHandle().level(), new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()))); ++ this.getHandle().containerMenu.checkReachable = !force; ++ return this.getHandle().containerMenu.getBukkitView(); ++ } ++ // Paper end ++ + @Override + public void closeInventory() { + // Paper start - Inventory close reason diff --git a/patches/server/0401-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch b/patches/server/0401-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch deleted file mode 100644 index 6b7040ff05..0000000000 --- a/patches/server/0401-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 25 Aug 2020 20:45:36 -0400 -Subject: [PATCH] Fix Entity Teleportation and cancel velocity if teleported - -Uses correct setPositionRotation for Entity teleporting instead of setLocation -as this is how Vanilla teleports entities. - -Cancel any pending motion when teleported. - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index eab19d5ac362c4779e91fad0ede3e4c26f29ab01..0d7dae5fa79cd302d73d1be51d8bf908a816c4ca 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -680,7 +680,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - return; - } - -- this.player.absMoveTo(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); -+ this.player.moveTo(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); // Paper - Fix Entity Teleportation and cancel velocity if teleported - this.lastGoodX = this.awaitingPositionFromClient.x; - this.lastGoodY = this.awaitingPositionFromClient.y; - this.lastGoodZ = this.awaitingPositionFromClient.z; -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 3860265a50b62fbd36c9e1b32680c3b62d5342a6..e93f8a9eefc082d66d0e1804c98d0df7db914cd8 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -180,6 +180,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - - // CraftBukkit start - private static final int CURRENT_LEVEL = 2; -+ public boolean preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; keep initial motion on first setPositionRotation - static boolean isLevelAtLeast(CompoundTag tag, int level) { - return tag.contains("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level; - } -@@ -1967,6 +1968,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public void moveTo(double x, double y, double z, float yaw, float pitch) { -+ // Paper start - Fix Entity Teleportation and cancel velocity if teleported -+ if (!preserveMotion) { -+ this.deltaMovement = Vec3.ZERO; -+ } else { -+ this.preserveMotion = false; -+ } -+ // Paper end - Fix Entity Teleportation and cancel velocity if teleported - this.setPosRaw(x, y, z); - this.setYRot(yaw); - this.setXRot(pitch); -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java -index 2db75673e525708d04bda9f6c9af80e7f8d361e6..be2b5f56f6f29c82c4fa9df33287d0ddb589f383 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java -@@ -79,6 +79,7 @@ public class DragonStrafePlayerPhase extends AbstractDragonPhaseInstance { - } - - DragonFireball dragonFireball = new DragonFireball(world, this.dragon, vec34.normalize()); -+ dragonFireball.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported - dragonFireball.moveTo(o, p, q, 0.0F, 0.0F); - if (new com.destroystokyo.paper.event.entity.EnderDragonShootFireballEvent((org.bukkit.entity.EnderDragon) dragon.getBukkitEntity(), (org.bukkit.entity.DragonFireball) dragonFireball.getBukkitEntity()).callEvent()) // Paper - EnderDragon Events - world.addFreshEntity(dragonFireball); -diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java -index 56dbe701a93eb9f1309bec92e5d3b310860a4dc5..1b6ec72f59504d2f420d6d5dcbed4d3b9115e3d8 100644 ---- a/src/main/java/net/minecraft/world/level/BaseSpawner.java -+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java -@@ -164,6 +164,7 @@ public abstract class BaseSpawner { - return; - } - -+ entity.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; preserve entity motion from tag - entity.moveTo(entity.getX(), entity.getY(), entity.getZ(), randomsource.nextFloat() * 360.0F, 0.0F); - if (entity instanceof Mob) { - Mob entityinsentient = (Mob) entity; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index ec122fa4e443290ff973797740172e07f8e736ca..609c768ba4d22e346acbc9422ce41e3b887fadb1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -241,7 +241,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - } - - // entity.setLocation() throws no event, and so cannot be cancelled -- this.entity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); -+ entity.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); // Paper - use proper moveTo, as per vanilla teleporting - // SPIGOT-619: Force sync head rotation also - this.entity.setYHeadRot(location.getYaw()); - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 0aa3fd9dce0cf90b1f74551c864e9ebf326eb1f3..e979681142bd08aeb00a98b79789a8f41b2a37af 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -603,6 +603,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - } - - ((AbstractHurtingProjectile) launch).projectileSource = this; -+ launch.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported - launch.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } else if (LlamaSpit.class.isAssignableFrom(projectile)) { - Location location = this.getEyeLocation(); diff --git a/patches/server/0402-Add-additional-open-container-api-to-HumanEntity.patch b/patches/server/0402-Add-additional-open-container-api-to-HumanEntity.patch deleted file mode 100644 index 4f9cf8d9d9..0000000000 --- a/patches/server/0402-Add-additional-open-container-api-to-HumanEntity.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Wed, 26 Aug 2020 02:12:31 -0400 -Subject: [PATCH] Add additional open container api to HumanEntity - -== AT == -public net/minecraft/world/level/block/state/BlockBehaviour getMenuProvider(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/MenuProvider; - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index b2ab430392fc0f214ba8c5383e3f3ad5c548bda2..9022555db0df8c269fc039c895422cf36c08097e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -471,6 +471,70 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - return this.getHandle().containerMenu.getBukkitView(); - } - -+ // Paper start - Add additional containers -+ @Override -+ public InventoryView openAnvil(Location location, boolean force) { -+ return this.openInventory(location, force, Material.ANVIL); -+ } -+ -+ @Override -+ public InventoryView openCartographyTable(Location location, boolean force) { -+ return this.openInventory(location, force, Material.CARTOGRAPHY_TABLE); -+ } -+ -+ @Override -+ public InventoryView openGrindstone(Location location, boolean force) { -+ return this.openInventory(location, force, Material.GRINDSTONE); -+ } -+ -+ @Override -+ public InventoryView openLoom(Location location, boolean force) { -+ return this.openInventory(location, force, Material.LOOM); -+ } -+ -+ @Override -+ public InventoryView openSmithingTable(Location location, boolean force) { -+ return this.openInventory(location, force, Material.SMITHING_TABLE); -+ } -+ -+ @Override -+ public InventoryView openStonecutter(Location location, boolean force) { -+ return this.openInventory(location, force, Material.STONECUTTER); -+ } -+ -+ private InventoryView openInventory(Location location, boolean force, Material material) { -+ org.spigotmc.AsyncCatcher.catchOp("open" + material); -+ if (location == null) { -+ location = this.getLocation(); -+ } -+ if (!force) { -+ Block block = location.getBlock(); -+ if (block.getType() != material) { -+ return null; -+ } -+ } -+ net.minecraft.world.level.block.Block block; -+ if (material == Material.ANVIL) { -+ block = Blocks.ANVIL; -+ } else if (material == Material.CARTOGRAPHY_TABLE) { -+ block = Blocks.CARTOGRAPHY_TABLE; -+ } else if (material == Material.GRINDSTONE) { -+ block = Blocks.GRINDSTONE; -+ } else if (material == Material.LOOM) { -+ block = Blocks.LOOM; -+ } else if (material == Material.SMITHING_TABLE) { -+ block = Blocks.SMITHING_TABLE; -+ } else if (material == Material.STONECUTTER) { -+ block = Blocks.STONECUTTER; -+ } else { -+ throw new IllegalArgumentException("Unsupported inventory type: " + material); -+ } -+ this.getHandle().openMenu(block.getMenuProvider(null, this.getHandle().level(), new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()))); -+ this.getHandle().containerMenu.checkReachable = !force; -+ return this.getHandle().containerMenu.getBukkitView(); -+ } -+ // Paper end -+ - @Override - public void closeInventory() { - // Paper start - Inventory close reason diff --git a/patches/server/0402-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch b/patches/server/0402-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch new file mode 100644 index 0000000000..9a0c6f1492 --- /dev/null +++ b/patches/server/0402-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 12 Sep 2020 17:21:38 -0400 +Subject: [PATCH] Cache DataFixerUpper Rewrite Rules on demand + +Mojang precaches every single potential rewrite rule that could ever +exist on server startup. This includes rules from all the way back to versions from 6+ years ago. + +This is the source of why the server hogs every CPU core at 100% every start. + +For anyone who hard resets for updates or has force upgraded their entire world, this +results in completely wasted cpu cycles. + +This massive CPU usage also delays server startup time. + +We improve this by making "min version to precache" that defaults to a future version +so that no rewrite rules are precached. + +someone who expects to be converting a lot chunks could theoretically set +-DPaper.minPrecachedDatafixVersion= as a startup +parameter and only build from that point on. + +However this will likely never be needed as the server will still run +the same cache logic on demand when it's actually needed. The only +cost would be some delay on the FIRST chunk conversion, but paper already +runs chunk conversions on another thread so this will likely never be +a concern for TPS. + +This patch will significantly reduce CPU use on startup, reduce memory usage, +and improve server startup time. + +diff --git a/src/main/java/com/mojang/datafixers/DataFixerBuilder.java b/src/main/java/com/mojang/datafixers/DataFixerBuilder.java +index 4232ce05ad7dd122a78a04ccef3b59d4caf542df..2cce259c738de2680e219d30dc3020458f4442d6 100644 +--- a/src/main/java/com/mojang/datafixers/DataFixerBuilder.java ++++ b/src/main/java/com/mojang/datafixers/DataFixerBuilder.java +@@ -29,8 +29,10 @@ public class DataFixerBuilder { + private final Int2ObjectSortedMap schemas = new Int2ObjectAVLTreeMap<>(); + private final List globalList = new ArrayList<>(); + private final IntSortedSet fixerVersions = new IntAVLTreeSet(); ++ private final int minDataFixPrecacheVersion; // Paper - Perf: Cache DataFixerUpper Rewrite Rules on demand + + public DataFixerBuilder(final int dataVersion) { ++ minDataFixPrecacheVersion = Integer.getInteger("Paper.minPrecachedDatafixVersion", dataVersion+1) * 10; // Paper - Perf: default to precache nothing - mojang stores versions * 10 to allow for 'sub versions' + this.dataVersion = dataVersion; + } + +@@ -88,6 +90,7 @@ public class DataFixerBuilder { + final IntIterator iterator = fixerUpper.fixerVersions().iterator(); + while (iterator.hasNext()) { + final int versionKey = iterator.nextInt(); ++ if (versionKey < minDataFixPrecacheVersion) continue; // Paper - Perf: Cache DataFixerUpper Rewrite Rules on demand + final Schema schema = schemas.get(versionKey); + for (final String typeName : schema.types()) { + if (!requiredTypeNames.contains(typeName)) { diff --git a/patches/server/0403-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch b/patches/server/0403-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch deleted file mode 100644 index 9a0c6f1492..0000000000 --- a/patches/server/0403-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Sat, 12 Sep 2020 17:21:38 -0400 -Subject: [PATCH] Cache DataFixerUpper Rewrite Rules on demand - -Mojang precaches every single potential rewrite rule that could ever -exist on server startup. This includes rules from all the way back to versions from 6+ years ago. - -This is the source of why the server hogs every CPU core at 100% every start. - -For anyone who hard resets for updates or has force upgraded their entire world, this -results in completely wasted cpu cycles. - -This massive CPU usage also delays server startup time. - -We improve this by making "min version to precache" that defaults to a future version -so that no rewrite rules are precached. - -someone who expects to be converting a lot chunks could theoretically set --DPaper.minPrecachedDatafixVersion= as a startup -parameter and only build from that point on. - -However this will likely never be needed as the server will still run -the same cache logic on demand when it's actually needed. The only -cost would be some delay on the FIRST chunk conversion, but paper already -runs chunk conversions on another thread so this will likely never be -a concern for TPS. - -This patch will significantly reduce CPU use on startup, reduce memory usage, -and improve server startup time. - -diff --git a/src/main/java/com/mojang/datafixers/DataFixerBuilder.java b/src/main/java/com/mojang/datafixers/DataFixerBuilder.java -index 4232ce05ad7dd122a78a04ccef3b59d4caf542df..2cce259c738de2680e219d30dc3020458f4442d6 100644 ---- a/src/main/java/com/mojang/datafixers/DataFixerBuilder.java -+++ b/src/main/java/com/mojang/datafixers/DataFixerBuilder.java -@@ -29,8 +29,10 @@ public class DataFixerBuilder { - private final Int2ObjectSortedMap schemas = new Int2ObjectAVLTreeMap<>(); - private final List globalList = new ArrayList<>(); - private final IntSortedSet fixerVersions = new IntAVLTreeSet(); -+ private final int minDataFixPrecacheVersion; // Paper - Perf: Cache DataFixerUpper Rewrite Rules on demand - - public DataFixerBuilder(final int dataVersion) { -+ minDataFixPrecacheVersion = Integer.getInteger("Paper.minPrecachedDatafixVersion", dataVersion+1) * 10; // Paper - Perf: default to precache nothing - mojang stores versions * 10 to allow for 'sub versions' - this.dataVersion = dataVersion; - } - -@@ -88,6 +90,7 @@ public class DataFixerBuilder { - final IntIterator iterator = fixerUpper.fixerVersions().iterator(); - while (iterator.hasNext()) { - final int versionKey = iterator.nextInt(); -+ if (versionKey < minDataFixPrecacheVersion) continue; // Paper - Perf: Cache DataFixerUpper Rewrite Rules on demand - final Schema schema = schemas.get(versionKey); - for (final String typeName : schema.types()) { - if (!requiredTypeNames.contains(typeName)) { diff --git a/patches/server/0403-Extend-block-drop-capture-to-capture-all-items-added.patch b/patches/server/0403-Extend-block-drop-capture-to-capture-all-items-added.patch new file mode 100644 index 0000000000..f8c5daee20 --- /dev/null +++ b/patches/server/0403-Extend-block-drop-capture-to-capture-all-items-added.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Thu, 17 Sep 2020 00:36:05 +0100 +Subject: [PATCH] Extend block drop capture to capture all items added to the + world + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index d32606cba7222aa538cca3882314f9f87f33684f..f6b91771445ab4f48525f24025a9f5249f176cd5 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1199,6 +1199,12 @@ 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 { ++ // 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); ++ return true; ++ } ++ // Paper end - capture all item additions to the world + // SPIGOT-6415: Don't call spawn event when reason is null. For example when an entity teleports to a new world. + if (spawnReason != null && !CraftEventFactory.doEntityAddEventCalling(this, entity, spawnReason)) { + return false; +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 86e4559da2344f228ef4d1c4ac3c115fa0266d23..546be40a8e4470fb5a6686072cdd342cdaa6fe15 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -435,10 +435,12 @@ public class ServerPlayerGameMode { + // return true; // CraftBukkit + } + // CraftBukkit start ++ java.util.List itemsToDrop = this.level.captureDrops; // Paper - capture all item additions to the world ++ this.level.captureDrops = null; // Paper - capture all item additions to the world; Remove this earlier so that we can actually drop stuff + if (event.isDropItems()) { +- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, this.level.captureDrops); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, itemsToDrop); // Paper - capture all item additions to the world + } +- this.level.captureDrops = null; ++ //this.level.captureDrops = null; // Paper - capture all item additions to the world; move up + + // Drop event experience + if (flag && event != null) { diff --git a/patches/server/0404-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch b/patches/server/0404-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch new file mode 100644 index 0000000000..9806d3ed44 --- /dev/null +++ b/patches/server/0404-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MeFisto94 +Date: Fri, 28 Aug 2020 01:41:26 +0200 +Subject: [PATCH] Expose the Entity Counter to allow plugins to use valid and + non-conflicting Entity Ids + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index d871b45ea22f1f2019ca1d1e0708d8861daec633..b8e63ccc00668713e5759aaf04597359870397f3 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -4760,4 +4760,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + + void accept(Entity entity, double x, double y, double z); + } ++ ++ // Paper start - Expose entity id counter ++ public static int nextEntityId() { ++ return ENTITY_COUNTER.incrementAndGet(); ++ } ++ // Paper end - Expose entity id counter + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 1e41803952f2410c8f1e213d8be8d141773853d3..78bc460fff7d537109883f1469500f6f536c598e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -527,6 +527,11 @@ public final class CraftMagicNumbers implements UnsafeValues { + Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!"); + return compound; + } ++ ++ @Override ++ public int nextEntityId() { ++ return net.minecraft.world.entity.Entity.nextEntityId(); ++ } + // Paper end + + /** diff --git a/patches/server/0404-Extend-block-drop-capture-to-capture-all-items-added.patch b/patches/server/0404-Extend-block-drop-capture-to-capture-all-items-added.patch deleted file mode 100644 index a483ce60ab..0000000000 --- a/patches/server/0404-Extend-block-drop-capture-to-capture-all-items-added.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Thu, 17 Sep 2020 00:36:05 +0100 -Subject: [PATCH] Extend block drop capture to capture all items added to the - world - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index f01fe053888f7f5124c6b157044dfd46ea98ae23..1ed0940d8bdc4210992a335b3691c1cd3a13580a 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1199,6 +1199,12 @@ 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 { -+ // 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); -+ return true; -+ } -+ // Paper end - capture all item additions to the world - // SPIGOT-6415: Don't call spawn event when reason is null. For example when an entity teleports to a new world. - if (spawnReason != null && !CraftEventFactory.doEntityAddEventCalling(this, entity, spawnReason)) { - return false; -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 86e4559da2344f228ef4d1c4ac3c115fa0266d23..546be40a8e4470fb5a6686072cdd342cdaa6fe15 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -435,10 +435,12 @@ public class ServerPlayerGameMode { - // return true; // CraftBukkit - } - // CraftBukkit start -+ java.util.List itemsToDrop = this.level.captureDrops; // Paper - capture all item additions to the world -+ this.level.captureDrops = null; // Paper - capture all item additions to the world; Remove this earlier so that we can actually drop stuff - if (event.isDropItems()) { -- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, this.level.captureDrops); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, itemsToDrop); // Paper - capture all item additions to the world - } -- this.level.captureDrops = null; -+ //this.level.captureDrops = null; // Paper - capture all item additions to the world; move up - - // Drop event experience - if (flag && event != null) { diff --git a/patches/server/0405-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch b/patches/server/0405-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch deleted file mode 100644 index 848aa202cd..0000000000 --- a/patches/server/0405-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MeFisto94 -Date: Fri, 28 Aug 2020 01:41:26 +0200 -Subject: [PATCH] Expose the Entity Counter to allow plugins to use valid and - non-conflicting Entity Ids - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index e93f8a9eefc082d66d0e1804c98d0df7db914cd8..56e4a5316e873c0a6fc3495bbfba6dc503cc9c9c 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4760,4 +4760,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - - void accept(Entity entity, double x, double y, double z); - } -+ -+ // Paper start - Expose entity id counter -+ public static int nextEntityId() { -+ return ENTITY_COUNTER.incrementAndGet(); -+ } -+ // Paper end - Expose entity id counter - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 1e41803952f2410c8f1e213d8be8d141773853d3..78bc460fff7d537109883f1469500f6f536c598e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -527,6 +527,11 @@ public final class CraftMagicNumbers implements UnsafeValues { - Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!"); - return compound; - } -+ -+ @Override -+ public int nextEntityId() { -+ return net.minecraft.world.entity.Entity.nextEntityId(); -+ } - // Paper end - - /** diff --git a/patches/server/0405-Lazily-track-plugin-scoreboards-by-default.patch b/patches/server/0405-Lazily-track-plugin-scoreboards-by-default.patch new file mode 100644 index 0000000000..28ae9df043 --- /dev/null +++ b/patches/server/0405-Lazily-track-plugin-scoreboards-by-default.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Steinborn +Date: Sat, 3 Oct 2020 04:15:09 -0400 +Subject: [PATCH] Lazily track plugin scoreboards by default + +On servers with plugins that constantly churn through scoreboards, there is a risk of +degraded GC performance due to the number of scoreboards held on by weak references. +Most plugins don't even need the (vanilla) functionality that requires all plugin +scoreboards to be tracked by the server. Instead, only track scoreboards when an +objective is added with a non-dummy criteria. + +This is a breaking change, however the change is a much more sensible default. In case +this breaks your workflow you can always force all scoreboards to be tracked with +settings.track-plugin-scoreboards in paper.yml. + +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java +index 5681630159bb52628e6cc391db324bbafe333414..c650fc3712de01184509a03f1d1b388859e163d7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java +@@ -20,6 +20,7 @@ import org.bukkit.scoreboard.Team; + + public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard { + final Scoreboard board; ++ boolean registeredGlobally = false; // Paper - Lazily track plugin scoreboards by default + + CraftScoreboard(Scoreboard board) { + this.board = board; +@@ -52,6 +53,12 @@ public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard { + Preconditions.checkArgument(renderType != null, "RenderType cannot be null"); + Preconditions.checkArgument(name.length() <= Short.MAX_VALUE, "The name '%s' is longer than the limit of 32767 characters (%s)", name, name.length()); + Preconditions.checkArgument(this.board.getObjective(name) == null, "An objective of name '%s' already exists", name); ++ // Paper start - lazily track plugin scoreboards ++ if (((CraftCriteria) criteria).criteria != net.minecraft.world.scores.criteria.ObjectiveCriteria.DUMMY && !this.registeredGlobally) { ++ net.minecraft.server.MinecraftServer.getServer().server.getScoreboardManager().registerScoreboardForVanilla(this); ++ this.registeredGlobally = true; ++ } ++ // Paper end - lazily track plugin scoreboards + net.minecraft.world.scores.Objective objective = this.board.addObjective(name, ((CraftCriteria) criteria).criteria, io.papermc.paper.adventure.PaperAdventure.asVanilla(displayName), CraftScoreboardTranslations.fromBukkitRender(renderType), true, null); + return new CraftObjective(this, objective); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java +index 40e348cae063bc1a814f8fcc3a2688c135f23bb5..c7ca6210d6ae37fe95068c9baa5fb654f95307e0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java +@@ -30,6 +30,7 @@ public final class CraftScoreboardManager implements ScoreboardManager { + + public CraftScoreboardManager(MinecraftServer minecraftserver, net.minecraft.world.scores.Scoreboard scoreboardServer) { + this.mainScoreboard = new CraftScoreboard(scoreboardServer); ++ mainScoreboard.registeredGlobally = true; // Paper + this.server = minecraftserver; + this.scoreboards.add(this.mainScoreboard); + } +@@ -43,10 +44,22 @@ public final class CraftScoreboardManager implements ScoreboardManager { + public CraftScoreboard getNewScoreboard() { + org.spigotmc.AsyncCatcher.catchOp("scoreboard creation"); // Spigot + CraftScoreboard scoreboard = new CraftScoreboard(new ServerScoreboard(this.server)); +- this.scoreboards.add(scoreboard); ++ // Paper start ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().scoreboards.trackPluginScoreboards) { ++ scoreboard.registeredGlobally = true; ++ scoreboards.add(scoreboard); ++ } ++ // Paper end + return scoreboard; + } + ++ // Paper start ++ public void registerScoreboardForVanilla(CraftScoreboard scoreboard) { ++ org.spigotmc.AsyncCatcher.catchOp("scoreboard registration"); ++ scoreboards.add(scoreboard); ++ } ++ // Paper end ++ + // CraftBukkit method + public CraftScoreboard getPlayerBoard(CraftPlayer player) { + CraftScoreboard board = this.playerBoards.get(player); diff --git a/patches/server/0406-Entity-isTicking.patch b/patches/server/0406-Entity-isTicking.patch new file mode 100644 index 0000000000..cd8df4b7db --- /dev/null +++ b/patches/server/0406-Entity-isTicking.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 3 Oct 2020 21:39:16 -0500 +Subject: [PATCH] Entity#isTicking + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index b8e63ccc00668713e5759aaf04597359870397f3..1efaae5d9dab0bbcc2bbef772eb0f5cdf8ff384c 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -4765,5 +4765,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public static int nextEntityId() { + return ENTITY_COUNTER.incrementAndGet(); + } ++ ++ public boolean isTicking() { ++ return ((net.minecraft.server.level.ServerLevel) this.level).isPositionEntityTicking(this.blockPosition()); ++ } + // Paper end - Expose entity id counter + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 609c768ba4d22e346acbc9422ce41e3b887fadb1..dbb1a52b1e5871bbb1ccbd300b8edb9aa0f56e49 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1058,4 +1058,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return getHandle().isInLava(); + } + // Paper end - entity liquid API ++ ++ // Paper start - isTicking API ++ @Override ++ public boolean isTicking() { ++ return getHandle().isTicking(); ++ } ++ // Paper end - isTicking API + } diff --git a/patches/server/0406-Lazily-track-plugin-scoreboards-by-default.patch b/patches/server/0406-Lazily-track-plugin-scoreboards-by-default.patch deleted file mode 100644 index 28ae9df043..0000000000 --- a/patches/server/0406-Lazily-track-plugin-scoreboards-by-default.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrew Steinborn -Date: Sat, 3 Oct 2020 04:15:09 -0400 -Subject: [PATCH] Lazily track plugin scoreboards by default - -On servers with plugins that constantly churn through scoreboards, there is a risk of -degraded GC performance due to the number of scoreboards held on by weak references. -Most plugins don't even need the (vanilla) functionality that requires all plugin -scoreboards to be tracked by the server. Instead, only track scoreboards when an -objective is added with a non-dummy criteria. - -This is a breaking change, however the change is a much more sensible default. In case -this breaks your workflow you can always force all scoreboards to be tracked with -settings.track-plugin-scoreboards in paper.yml. - -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java -index 5681630159bb52628e6cc391db324bbafe333414..c650fc3712de01184509a03f1d1b388859e163d7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java -@@ -20,6 +20,7 @@ import org.bukkit.scoreboard.Team; - - public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard { - final Scoreboard board; -+ boolean registeredGlobally = false; // Paper - Lazily track plugin scoreboards by default - - CraftScoreboard(Scoreboard board) { - this.board = board; -@@ -52,6 +53,12 @@ public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard { - Preconditions.checkArgument(renderType != null, "RenderType cannot be null"); - Preconditions.checkArgument(name.length() <= Short.MAX_VALUE, "The name '%s' is longer than the limit of 32767 characters (%s)", name, name.length()); - Preconditions.checkArgument(this.board.getObjective(name) == null, "An objective of name '%s' already exists", name); -+ // Paper start - lazily track plugin scoreboards -+ if (((CraftCriteria) criteria).criteria != net.minecraft.world.scores.criteria.ObjectiveCriteria.DUMMY && !this.registeredGlobally) { -+ net.minecraft.server.MinecraftServer.getServer().server.getScoreboardManager().registerScoreboardForVanilla(this); -+ this.registeredGlobally = true; -+ } -+ // Paper end - lazily track plugin scoreboards - net.minecraft.world.scores.Objective objective = this.board.addObjective(name, ((CraftCriteria) criteria).criteria, io.papermc.paper.adventure.PaperAdventure.asVanilla(displayName), CraftScoreboardTranslations.fromBukkitRender(renderType), true, null); - return new CraftObjective(this, objective); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -index 40e348cae063bc1a814f8fcc3a2688c135f23bb5..c7ca6210d6ae37fe95068c9baa5fb654f95307e0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -@@ -30,6 +30,7 @@ public final class CraftScoreboardManager implements ScoreboardManager { - - public CraftScoreboardManager(MinecraftServer minecraftserver, net.minecraft.world.scores.Scoreboard scoreboardServer) { - this.mainScoreboard = new CraftScoreboard(scoreboardServer); -+ mainScoreboard.registeredGlobally = true; // Paper - this.server = minecraftserver; - this.scoreboards.add(this.mainScoreboard); - } -@@ -43,10 +44,22 @@ public final class CraftScoreboardManager implements ScoreboardManager { - public CraftScoreboard getNewScoreboard() { - org.spigotmc.AsyncCatcher.catchOp("scoreboard creation"); // Spigot - CraftScoreboard scoreboard = new CraftScoreboard(new ServerScoreboard(this.server)); -- this.scoreboards.add(scoreboard); -+ // Paper start -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().scoreboards.trackPluginScoreboards) { -+ scoreboard.registeredGlobally = true; -+ scoreboards.add(scoreboard); -+ } -+ // Paper end - return scoreboard; - } - -+ // Paper start -+ public void registerScoreboardForVanilla(CraftScoreboard scoreboard) { -+ org.spigotmc.AsyncCatcher.catchOp("scoreboard registration"); -+ scoreboards.add(scoreboard); -+ } -+ // Paper end -+ - // CraftBukkit method - public CraftScoreboard getPlayerBoard(CraftPlayer player) { - CraftScoreboard board = this.playerBoards.get(player); diff --git a/patches/server/0407-Entity-isTicking.patch b/patches/server/0407-Entity-isTicking.patch deleted file mode 100644 index f4c67478a8..0000000000 --- a/patches/server/0407-Entity-isTicking.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 3 Oct 2020 21:39:16 -0500 -Subject: [PATCH] Entity#isTicking - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 56e4a5316e873c0a6fc3495bbfba6dc503cc9c9c..7609a58979388cb62be7ae94a51cc14774464214 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4765,5 +4765,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public static int nextEntityId() { - return ENTITY_COUNTER.incrementAndGet(); - } -+ -+ public boolean isTicking() { -+ return ((net.minecraft.server.level.ServerLevel) this.level).isPositionEntityTicking(this.blockPosition()); -+ } - // Paper end - Expose entity id counter - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 609c768ba4d22e346acbc9422ce41e3b887fadb1..dbb1a52b1e5871bbb1ccbd300b8edb9aa0f56e49 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1058,4 +1058,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return getHandle().isInLava(); - } - // Paper end - entity liquid API -+ -+ // Paper start - isTicking API -+ @Override -+ public boolean isTicking() { -+ return getHandle().isTicking(); -+ } -+ // Paper end - isTicking API - } diff --git a/patches/server/0407-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch b/patches/server/0407-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch new file mode 100644 index 0000000000..70bf2759a9 --- /dev/null +++ b/patches/server/0407-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 3 Oct 2020 22:00:27 -0500 +Subject: [PATCH] Fix deop kicking non-whitelisted player when white list is + not enabled + + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 6292256864aa0a265a73c0ef2af642d4ab387ccc..c036c391172ffb4b14b7a5f77776a68e3670775c 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -2309,13 +2309,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop list = Lists.newArrayList(playerlist.getPlayers()); + Iterator iterator = list.iterator(); + + while (iterator.hasNext()) { + ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + +- if (!whitelist.isWhiteListed(entityplayer.getGameProfile())) { ++ if (!whitelist.isWhiteListed(entityplayer.getGameProfile()) && !this.getPlayerList().isOp(entityplayer.getGameProfile())) { // Paper - Fix kicking ops when whitelist is reloaded (MC-171420) + entityplayer.connection.disconnect((Component) Component.translatable("multiplayer.disconnect.not_whitelisted")); + } + } diff --git a/patches/server/0408-Fix-Concurrency-issue-in-ShufflingList.patch b/patches/server/0408-Fix-Concurrency-issue-in-ShufflingList.patch new file mode 100644 index 0000000000..f04a40e1ac --- /dev/null +++ b/patches/server/0408-Fix-Concurrency-issue-in-ShufflingList.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 6 Jul 2020 18:36:41 -0400 +Subject: [PATCH] Fix Concurrency issue in ShufflingList + +if multiple threads from worldgen sort at same time, it will crash. +So make a copy of the list for sorting purposes. + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java +index 334962f1bf5988059fec506f0d3aaf4302205220..6a270c9adb044a6e0b1c8e09b9106d51989fd761 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java +@@ -18,7 +18,7 @@ public class GateBehavior implements BehaviorControl + private final Set> exitErasedMemories; + private final GateBehavior.OrderPolicy orderPolicy; + private final GateBehavior.RunningPolicy runningPolicy; +- private final ShufflingList> behaviors = new ShufflingList<>(); ++ private final ShufflingList> behaviors = new ShufflingList<>(false); // Paper - Fix Concurrency issue in ShufflingList during worldgen + private Behavior.Status status = Behavior.Status.STOPPED; + + public GateBehavior( +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java +index 195eea55fabc7a9a665e0a8f04934a3aaf9f8b71..3fac11bf02652b5f51f30f99bdf516504467d0d2 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java +@@ -16,12 +16,25 @@ import net.minecraft.util.RandomSource; + public class ShufflingList implements Iterable { + protected final List> entries; + private final RandomSource random = RandomSource.create(); ++ private final boolean isUnsafe; // Paper - Fix Concurrency issue in ShufflingList during worldgen + + public ShufflingList() { ++ // Paper start - Fix Concurrency issue in ShufflingList during worldgen ++ this(true); ++ } ++ public ShufflingList(boolean isUnsafe) { ++ this.isUnsafe = isUnsafe; ++ // Paper end - Fix Concurrency issue in ShufflingList during worldgen + this.entries = Lists.newArrayList(); + } + + private ShufflingList(List> list) { ++ // Paper start - Fix Concurrency issue in ShufflingList during worldgen ++ this(list, true); ++ } ++ private ShufflingList(List> list, boolean isUnsafe) { ++ this.isUnsafe = isUnsafe; ++ // Paper end - Fix Concurrency issue in ShufflingList during worldgen + this.entries = Lists.newArrayList(list); + } + +@@ -35,9 +48,12 @@ public class ShufflingList implements Iterable { + } + + public ShufflingList shuffle() { +- this.entries.forEach(entry -> entry.setRandom(this.random.nextFloat())); +- this.entries.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight)); +- return this; ++ // Paper start - Fix Concurrency issue in ShufflingList during worldgen ++ List> list = this.isUnsafe ? Lists.newArrayList(this.entries) : this.entries; ++ list.forEach(entry -> entry.setRandom(this.random.nextFloat())); ++ list.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight)); ++ return this.isUnsafe ? new ShufflingList<>(list, this.isUnsafe) : this; ++ // Paper end - Fix Concurrency issue in ShufflingList during worldgen + } + + public Stream stream() { diff --git a/patches/server/0408-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch b/patches/server/0408-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch deleted file mode 100644 index 70bf2759a9..0000000000 --- a/patches/server/0408-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 3 Oct 2020 22:00:27 -0500 -Subject: [PATCH] Fix deop kicking non-whitelisted player when white list is - not enabled - - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 6292256864aa0a265a73c0ef2af642d4ab387ccc..c036c391172ffb4b14b7a5f77776a68e3670775c 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2309,13 +2309,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop list = Lists.newArrayList(playerlist.getPlayers()); - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); - -- if (!whitelist.isWhiteListed(entityplayer.getGameProfile())) { -+ if (!whitelist.isWhiteListed(entityplayer.getGameProfile()) && !this.getPlayerList().isOp(entityplayer.getGameProfile())) { // Paper - Fix kicking ops when whitelist is reloaded (MC-171420) - entityplayer.connection.disconnect((Component) Component.translatable("multiplayer.disconnect.not_whitelisted")); - } - } diff --git a/patches/server/0409-Fix-Concurrency-issue-in-ShufflingList.patch b/patches/server/0409-Fix-Concurrency-issue-in-ShufflingList.patch deleted file mode 100644 index f04a40e1ac..0000000000 --- a/patches/server/0409-Fix-Concurrency-issue-in-ShufflingList.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 6 Jul 2020 18:36:41 -0400 -Subject: [PATCH] Fix Concurrency issue in ShufflingList - -if multiple threads from worldgen sort at same time, it will crash. -So make a copy of the list for sorting purposes. - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java -index 334962f1bf5988059fec506f0d3aaf4302205220..6a270c9adb044a6e0b1c8e09b9106d51989fd761 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java -@@ -18,7 +18,7 @@ public class GateBehavior implements BehaviorControl - private final Set> exitErasedMemories; - private final GateBehavior.OrderPolicy orderPolicy; - private final GateBehavior.RunningPolicy runningPolicy; -- private final ShufflingList> behaviors = new ShufflingList<>(); -+ private final ShufflingList> behaviors = new ShufflingList<>(false); // Paper - Fix Concurrency issue in ShufflingList during worldgen - private Behavior.Status status = Behavior.Status.STOPPED; - - public GateBehavior( -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java -index 195eea55fabc7a9a665e0a8f04934a3aaf9f8b71..3fac11bf02652b5f51f30f99bdf516504467d0d2 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java -@@ -16,12 +16,25 @@ import net.minecraft.util.RandomSource; - public class ShufflingList implements Iterable { - protected final List> entries; - private final RandomSource random = RandomSource.create(); -+ private final boolean isUnsafe; // Paper - Fix Concurrency issue in ShufflingList during worldgen - - public ShufflingList() { -+ // Paper start - Fix Concurrency issue in ShufflingList during worldgen -+ this(true); -+ } -+ public ShufflingList(boolean isUnsafe) { -+ this.isUnsafe = isUnsafe; -+ // Paper end - Fix Concurrency issue in ShufflingList during worldgen - this.entries = Lists.newArrayList(); - } - - private ShufflingList(List> list) { -+ // Paper start - Fix Concurrency issue in ShufflingList during worldgen -+ this(list, true); -+ } -+ private ShufflingList(List> list, boolean isUnsafe) { -+ this.isUnsafe = isUnsafe; -+ // Paper end - Fix Concurrency issue in ShufflingList during worldgen - this.entries = Lists.newArrayList(list); - } - -@@ -35,9 +48,12 @@ public class ShufflingList implements Iterable { - } - - public ShufflingList shuffle() { -- this.entries.forEach(entry -> entry.setRandom(this.random.nextFloat())); -- this.entries.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight)); -- return this; -+ // Paper start - Fix Concurrency issue in ShufflingList during worldgen -+ List> list = this.isUnsafe ? Lists.newArrayList(this.entries) : this.entries; -+ list.forEach(entry -> entry.setRandom(this.random.nextFloat())); -+ list.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight)); -+ return this.isUnsafe ? new ShufflingList<>(list, this.isUnsafe) : this; -+ // Paper end - Fix Concurrency issue in ShufflingList during worldgen - } - - public Stream stream() { diff --git a/patches/server/0409-Reset-Ender-Crystals-on-Dragon-Spawn.patch b/patches/server/0409-Reset-Ender-Crystals-on-Dragon-Spawn.patch new file mode 100644 index 0000000000..0c53eb55ed --- /dev/null +++ b/patches/server/0409-Reset-Ender-Crystals-on-Dragon-Spawn.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 1 Jun 2016 23:29:17 -0400 +Subject: [PATCH] Reset Ender Crystals on Dragon Spawn + +Crystals can end up in a bad state in certain conditions which causes +an exception on the expected number of crystals going negative. + +This ensures the crystals/pillars are in expected state when the dragon spawns. + +See #3522 + +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 a16229f5eaa9e8320751e4fd1faf016f796d3414..0f34a5ce0352f627099a719b78e530e5e572581a 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 +@@ -475,6 +475,7 @@ public class EndDragonFight { + entityenderdragon.moveTo((double) this.origin.getX(), (double) (128 + this.origin.getY()), (double) this.origin.getZ(), this.level.random.nextFloat() * 360.0F, 0.0F); + this.level.addFreshEntity(entityenderdragon); + this.dragonUUID = entityenderdragon.getUUID(); ++ this.resetSpikeCrystals(); // Paper - Reset ender crystals on dragon spawn + } + + return entityenderdragon; diff --git a/patches/server/0410-Fix-for-large-move-vectors-crashing-server.patch b/patches/server/0410-Fix-for-large-move-vectors-crashing-server.patch new file mode 100644 index 0000000000..2eef81bb77 --- /dev/null +++ b/patches/server/0410-Fix-for-large-move-vectors-crashing-server.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 17 May 2020 23:47:33 -0700 +Subject: [PATCH] Fix for large move vectors crashing server + +Check movement distance also based on current position. + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 0d7dae5fa79cd302d73d1be51d8bf908a816c4ca..1e6c8a23e892fc1c49da9538b435aa3eb0a28934 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -499,9 +499,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + float prevYaw = this.player.getYRot(); + float prevPitch = this.player.getXRot(); + // CraftBukkit end +- double d0 = entity.getX(); +- double d1 = entity.getY(); +- double d2 = entity.getZ(); ++ double d0 = entity.getX(); final double fromX = d0; // Paper - OBFHELPER ++ double d1 = entity.getY(); final double fromY = d1; // Paper - OBFHELPER ++ double d2 = entity.getZ(); final double fromZ = d2; // Paper - OBFHELPER + double d3 = ServerGamePacketListenerImpl.clampHorizontal(packet.position().x()); final double toX = d3; // Paper - OBFHELPER + double d4 = ServerGamePacketListenerImpl.clampVertical(packet.position().y()); final double toY = d4; // Paper - OBFHELPER + double d5 = ServerGamePacketListenerImpl.clampHorizontal(packet.position().z()); final double toZ = d5; // Paper - OBFHELPER +@@ -511,7 +511,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + double d7 = d4 - this.vehicleFirstGoodY; + double d8 = d5 - this.vehicleFirstGoodZ; + double d9 = entity.getDeltaMovement().lengthSqr(); +- double d10 = d6 * d6 + d7 * d7 + d8 * d8; ++ // Paper start - fix large move vectors killing the server ++ double currDeltaX = toX - fromX; ++ double currDeltaY = toY - fromY; ++ double currDeltaZ = toZ - fromZ; ++ double d10 = Math.max(d6 * d6 + d7 * d7 + d8 * d8, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); ++ double otherFieldX = d3 - this.vehicleLastGoodX; ++ double otherFieldY = d4 - this.vehicleLastGoodY; ++ double otherFieldZ = d5 - this.vehicleLastGoodZ; ++ d10 = Math.max(d10, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); ++ // Paper end - fix large move vectors killing the server + + // CraftBukkit start - handle custom speeds and skipped ticks + this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick; +@@ -557,9 +566,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + boolean flag = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D)); + +- d6 = d3 - this.vehicleLastGoodX; +- d7 = d4 - this.vehicleLastGoodY; +- d8 = d5 - this.vehicleLastGoodZ; ++ d6 = d3 - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above ++ d7 = d4 - this.vehicleLastGoodY; // Paper - diff on change, used for checking large move vectors above ++ d8 = d5 - this.vehicleLastGoodZ; // Paper - diff on change, used for checking large move vectors above + boolean flag1 = entity.verticalCollisionBelow; + + if (entity instanceof LivingEntity) { +@@ -1318,7 +1327,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + double d7 = d1 - this.firstGoodY; + double d8 = d2 - this.firstGoodZ; + double d9 = this.player.getDeltaMovement().lengthSqr(); +- double d10 = d6 * d6 + d7 * d7 + d8 * d8; ++ // Paper start - fix large move vectors killing the server ++ double currDeltaX = toX - prevX; ++ double currDeltaY = toY - prevY; ++ double currDeltaZ = toZ - prevZ; ++ double d10 = Math.max(d6 * d6 + d7 * d7 + d8 * d8, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); ++ double otherFieldX = d0 - this.lastGoodX; ++ double otherFieldY = d1 - this.lastGoodY; ++ double otherFieldZ = d2 - this.lastGoodZ; ++ d10 = Math.max(d10, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); ++ // Paper end - fix large move vectors killing the server + + if (this.player.isSleeping()) { + if (d10 > 1.0D) { +@@ -1374,9 +1392,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + AABB axisalignedbb = this.player.getBoundingBox(); + +- d6 = d0 - this.lastGoodX; +- d7 = d1 - this.lastGoodY; +- d8 = d2 - this.lastGoodZ; ++ d6 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above ++ d7 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above ++ d8 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above + boolean flag1 = d7 > 0.0D; + + if (this.player.onGround() && !packet.isOnGround() && flag1) { diff --git a/patches/server/0410-Reset-Ender-Crystals-on-Dragon-Spawn.patch b/patches/server/0410-Reset-Ender-Crystals-on-Dragon-Spawn.patch deleted file mode 100644 index 0c53eb55ed..0000000000 --- a/patches/server/0410-Reset-Ender-Crystals-on-Dragon-Spawn.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 1 Jun 2016 23:29:17 -0400 -Subject: [PATCH] Reset Ender Crystals on Dragon Spawn - -Crystals can end up in a bad state in certain conditions which causes -an exception on the expected number of crystals going negative. - -This ensures the crystals/pillars are in expected state when the dragon spawns. - -See #3522 - -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 a16229f5eaa9e8320751e4fd1faf016f796d3414..0f34a5ce0352f627099a719b78e530e5e572581a 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 -@@ -475,6 +475,7 @@ public class EndDragonFight { - entityenderdragon.moveTo((double) this.origin.getX(), (double) (128 + this.origin.getY()), (double) this.origin.getZ(), this.level.random.nextFloat() * 360.0F, 0.0F); - this.level.addFreshEntity(entityenderdragon); - this.dragonUUID = entityenderdragon.getUUID(); -+ this.resetSpikeCrystals(); // Paper - Reset ender crystals on dragon spawn - } - - return entityenderdragon; diff --git a/patches/server/0411-Fix-for-large-move-vectors-crashing-server.patch b/patches/server/0411-Fix-for-large-move-vectors-crashing-server.patch deleted file mode 100644 index 2eef81bb77..0000000000 --- a/patches/server/0411-Fix-for-large-move-vectors-crashing-server.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 17 May 2020 23:47:33 -0700 -Subject: [PATCH] Fix for large move vectors crashing server - -Check movement distance also based on current position. - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 0d7dae5fa79cd302d73d1be51d8bf908a816c4ca..1e6c8a23e892fc1c49da9538b435aa3eb0a28934 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -499,9 +499,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - float prevYaw = this.player.getYRot(); - float prevPitch = this.player.getXRot(); - // CraftBukkit end -- double d0 = entity.getX(); -- double d1 = entity.getY(); -- double d2 = entity.getZ(); -+ double d0 = entity.getX(); final double fromX = d0; // Paper - OBFHELPER -+ double d1 = entity.getY(); final double fromY = d1; // Paper - OBFHELPER -+ double d2 = entity.getZ(); final double fromZ = d2; // Paper - OBFHELPER - double d3 = ServerGamePacketListenerImpl.clampHorizontal(packet.position().x()); final double toX = d3; // Paper - OBFHELPER - double d4 = ServerGamePacketListenerImpl.clampVertical(packet.position().y()); final double toY = d4; // Paper - OBFHELPER - double d5 = ServerGamePacketListenerImpl.clampHorizontal(packet.position().z()); final double toZ = d5; // Paper - OBFHELPER -@@ -511,7 +511,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - double d7 = d4 - this.vehicleFirstGoodY; - double d8 = d5 - this.vehicleFirstGoodZ; - double d9 = entity.getDeltaMovement().lengthSqr(); -- double d10 = d6 * d6 + d7 * d7 + d8 * d8; -+ // Paper start - fix large move vectors killing the server -+ double currDeltaX = toX - fromX; -+ double currDeltaY = toY - fromY; -+ double currDeltaZ = toZ - fromZ; -+ double d10 = Math.max(d6 * d6 + d7 * d7 + d8 * d8, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); -+ double otherFieldX = d3 - this.vehicleLastGoodX; -+ double otherFieldY = d4 - this.vehicleLastGoodY; -+ double otherFieldZ = d5 - this.vehicleLastGoodZ; -+ d10 = Math.max(d10, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); -+ // Paper end - fix large move vectors killing the server - - // CraftBukkit start - handle custom speeds and skipped ticks - this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick; -@@ -557,9 +566,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - boolean flag = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D)); - -- d6 = d3 - this.vehicleLastGoodX; -- d7 = d4 - this.vehicleLastGoodY; -- d8 = d5 - this.vehicleLastGoodZ; -+ d6 = d3 - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above -+ d7 = d4 - this.vehicleLastGoodY; // Paper - diff on change, used for checking large move vectors above -+ d8 = d5 - this.vehicleLastGoodZ; // Paper - diff on change, used for checking large move vectors above - boolean flag1 = entity.verticalCollisionBelow; - - if (entity instanceof LivingEntity) { -@@ -1318,7 +1327,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - double d7 = d1 - this.firstGoodY; - double d8 = d2 - this.firstGoodZ; - double d9 = this.player.getDeltaMovement().lengthSqr(); -- double d10 = d6 * d6 + d7 * d7 + d8 * d8; -+ // Paper start - fix large move vectors killing the server -+ double currDeltaX = toX - prevX; -+ double currDeltaY = toY - prevY; -+ double currDeltaZ = toZ - prevZ; -+ double d10 = Math.max(d6 * d6 + d7 * d7 + d8 * d8, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); -+ double otherFieldX = d0 - this.lastGoodX; -+ double otherFieldY = d1 - this.lastGoodY; -+ double otherFieldZ = d2 - this.lastGoodZ; -+ d10 = Math.max(d10, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); -+ // Paper end - fix large move vectors killing the server - - if (this.player.isSleeping()) { - if (d10 > 1.0D) { -@@ -1374,9 +1392,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - AABB axisalignedbb = this.player.getBoundingBox(); - -- d6 = d0 - this.lastGoodX; -- d7 = d1 - this.lastGoodY; -- d8 = d2 - this.lastGoodZ; -+ d6 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above -+ d7 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above -+ d8 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above - boolean flag1 = d7 > 0.0D; - - if (this.player.onGround() && !packet.isOnGround() && flag1) { diff --git a/patches/server/0411-Optimise-getType-calls.patch b/patches/server/0411-Optimise-getType-calls.patch new file mode 100644 index 0000000000..da94b3a7b4 --- /dev/null +++ b/patches/server/0411-Optimise-getType-calls.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Wed, 3 Jun 2020 11:37:13 -0700 +Subject: [PATCH] Optimise getType calls + +Remove the map lookup for converting from Block->Bukkit Material + +diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockState.java b/src/main/java/net/minecraft/world/level/block/state/BlockState.java +index 065d140ca4f987e14138a37f4c7d60879dd7b6e1..601135f3368272bf1ca3a43ec9c199e3ee838462 100644 +--- a/src/main/java/net/minecraft/world/level/block/state/BlockState.java ++++ b/src/main/java/net/minecraft/world/level/block/state/BlockState.java +@@ -10,6 +10,16 @@ import net.minecraft.world.level.block.state.properties.Property; + public class BlockState extends BlockBehaviour.BlockStateBase { + public static final Codec CODEC = codec(BuiltInRegistries.BLOCK.byNameCodec(), Block::defaultBlockState).stable(); + ++ // Paper start - optimise getType calls ++ org.bukkit.Material cachedMaterial; ++ ++ public final org.bukkit.Material getBukkitMaterial() { ++ if (this.cachedMaterial == null) { ++ this.cachedMaterial = org.bukkit.craftbukkit.block.CraftBlockType.minecraftToBukkit(this.getBlock()); ++ } ++ return this.cachedMaterial; ++ } ++ // Paper end - optimise getType calls + public BlockState(Block block, Reference2ObjectArrayMap, Comparable> propertyMap, MapCodec codec) { + super(block, propertyMap, codec); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java +index a845ebd6262e05a1395c9a503480319e4b4a65ce..c88e4ba701b2a2325b76478b7f47278157afd2ef 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java +@@ -100,7 +100,7 @@ public class CraftChunkSnapshot implements ChunkSnapshot { + public Material getBlockType(int x, int y, int z) { + this.validateChunkCoordinates(x, y, z); + +- return CraftBlockType.minecraftToBukkit(this.blockids[this.getSectionIndex(y)].get(x, y & 0xF, z).getBlock()); ++ return this.blockids[this.getSectionIndex(y)].get(x, y & 0xF, z).getBukkitMaterial(); // Paper - optimise getType calls + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 3fa3de9a89550ec2fcb8ca663742826c0c3136b6..5f4dcf6d86db66186dc31075bdb739f5dbae6480 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -220,7 +220,7 @@ public class CraftBlock implements Block { + + @Override + public Material getType() { +- return CraftBlockType.minecraftToBukkit(this.world.getBlockState(this.position).getBlock()); ++ return this.world.getBlockState(this.position).getBukkitMaterial(); // Paper - optimise getType calls + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +index fabdec2d66cc6d676ed58fa570e2c318ab0927e2..1002123cd0c6f57cecc4e80f5f21cc6ff5886d37 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +@@ -175,7 +175,7 @@ public class CraftBlockState implements BlockState { + + @Override + public Material getType() { +- return CraftBlockType.minecraftToBukkit(this.data.getBlock()); ++ return this.data.getBukkitMaterial(); // Paper - optimise getType calls + } + + public void setFlag(int flag) { +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 22b8603a0eb7e981ca3483b37d3b7af28f300dfd..4982950b13cdf1668c0a662b80faf9f700ed584b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +@@ -63,7 +63,7 @@ public class CraftBlockData implements BlockData { + + @Override + public Material getMaterial() { +- return CraftBlockType.minecraftToBukkit(this.state.getBlock()); ++ return this.state.getBukkitMaterial(); // Paper - optimise getType calls + } + + public net.minecraft.world.level.block.state.BlockState getState() { +diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java +index c96aaa185d9d929cb19f427be82053f0cfa13bad..0fb580530d0b6d4d63ea4b85fec9240eb5c74df4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java ++++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java +@@ -96,7 +96,7 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData { + + @Override + public Material getType(int x, int y, int z) { +- return CraftBlockType.minecraftToBukkit(this.getTypeId(x, y, z).getBlock()); ++ return this.getTypeId(x, y, z).getBukkitMaterial(); // Paper - optimise getType calls + } + + @Override diff --git a/patches/server/0412-Optimise-getType-calls.patch b/patches/server/0412-Optimise-getType-calls.patch deleted file mode 100644 index da94b3a7b4..0000000000 --- a/patches/server/0412-Optimise-getType-calls.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Wed, 3 Jun 2020 11:37:13 -0700 -Subject: [PATCH] Optimise getType calls - -Remove the map lookup for converting from Block->Bukkit Material - -diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockState.java b/src/main/java/net/minecraft/world/level/block/state/BlockState.java -index 065d140ca4f987e14138a37f4c7d60879dd7b6e1..601135f3368272bf1ca3a43ec9c199e3ee838462 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/BlockState.java -+++ b/src/main/java/net/minecraft/world/level/block/state/BlockState.java -@@ -10,6 +10,16 @@ import net.minecraft.world.level.block.state.properties.Property; - public class BlockState extends BlockBehaviour.BlockStateBase { - public static final Codec CODEC = codec(BuiltInRegistries.BLOCK.byNameCodec(), Block::defaultBlockState).stable(); - -+ // Paper start - optimise getType calls -+ org.bukkit.Material cachedMaterial; -+ -+ public final org.bukkit.Material getBukkitMaterial() { -+ if (this.cachedMaterial == null) { -+ this.cachedMaterial = org.bukkit.craftbukkit.block.CraftBlockType.minecraftToBukkit(this.getBlock()); -+ } -+ return this.cachedMaterial; -+ } -+ // Paper end - optimise getType calls - public BlockState(Block block, Reference2ObjectArrayMap, Comparable> propertyMap, MapCodec codec) { - super(block, propertyMap, codec); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java -index a845ebd6262e05a1395c9a503480319e4b4a65ce..c88e4ba701b2a2325b76478b7f47278157afd2ef 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java -@@ -100,7 +100,7 @@ public class CraftChunkSnapshot implements ChunkSnapshot { - public Material getBlockType(int x, int y, int z) { - this.validateChunkCoordinates(x, y, z); - -- return CraftBlockType.minecraftToBukkit(this.blockids[this.getSectionIndex(y)].get(x, y & 0xF, z).getBlock()); -+ return this.blockids[this.getSectionIndex(y)].get(x, y & 0xF, z).getBukkitMaterial(); // Paper - optimise getType calls - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 3fa3de9a89550ec2fcb8ca663742826c0c3136b6..5f4dcf6d86db66186dc31075bdb739f5dbae6480 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -220,7 +220,7 @@ public class CraftBlock implements Block { - - @Override - public Material getType() { -- return CraftBlockType.minecraftToBukkit(this.world.getBlockState(this.position).getBlock()); -+ return this.world.getBlockState(this.position).getBukkitMaterial(); // Paper - optimise getType calls - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -index fabdec2d66cc6d676ed58fa570e2c318ab0927e2..1002123cd0c6f57cecc4e80f5f21cc6ff5886d37 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -@@ -175,7 +175,7 @@ public class CraftBlockState implements BlockState { - - @Override - public Material getType() { -- return CraftBlockType.minecraftToBukkit(this.data.getBlock()); -+ return this.data.getBukkitMaterial(); // Paper - optimise getType calls - } - - public void setFlag(int flag) { -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 22b8603a0eb7e981ca3483b37d3b7af28f300dfd..4982950b13cdf1668c0a662b80faf9f700ed584b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -@@ -63,7 +63,7 @@ public class CraftBlockData implements BlockData { - - @Override - public Material getMaterial() { -- return CraftBlockType.minecraftToBukkit(this.state.getBlock()); -+ return this.state.getBukkitMaterial(); // Paper - optimise getType calls - } - - public net.minecraft.world.level.block.state.BlockState getState() { -diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java -index c96aaa185d9d929cb19f427be82053f0cfa13bad..0fb580530d0b6d4d63ea4b85fec9240eb5c74df4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java -+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java -@@ -96,7 +96,7 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData { - - @Override - public Material getType(int x, int y, int z) { -- return CraftBlockType.minecraftToBukkit(this.getTypeId(x, y, z).getBlock()); -+ return this.getTypeId(x, y, z).getBukkitMaterial(); // Paper - optimise getType calls - } - - @Override diff --git a/patches/server/0412-Villager-resetOffers.patch b/patches/server/0412-Villager-resetOffers.patch new file mode 100644 index 0000000000..1c9cac618a --- /dev/null +++ b/patches/server/0412-Villager-resetOffers.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 7 Oct 2019 00:15:37 -0500 +Subject: [PATCH] Villager#resetOffers + + +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 e5ce76abb09c91b881dee732c5985c53db552dfc..deac9d6389493213e2b0cc8e2b6ae0c9f055c011 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java +@@ -114,6 +114,13 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa + return this.tradingPlayer != null; + } + ++ // Paper start - Villager#resetOffers ++ public void resetOffers() { ++ this.offers = new MerchantOffers(); ++ this.updateTrades(); ++ } ++ // Paper end - Villager#resetOffers ++ + @Override + public MerchantOffers getOffers() { + if (this.level().isClientSide) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java +index e5f733a765068b5640e811abf9fda945a9e91c7c..3199f04d00836a0a51547c679f3f3c80d00da502 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java +@@ -34,4 +34,11 @@ public class CraftAbstractVillager extends CraftAgeable implements CraftMerchant + public Inventory getInventory() { + return new CraftInventory(this.getHandle().getInventory()); + } ++ ++ // Paper start - Villager#resetOffers ++ @Override ++ public void resetOffers() { ++ getHandle().resetOffers(); ++ } ++ // Paper end - Villager#resetOffers + } diff --git a/patches/server/0413-Retain-block-place-order-when-capturing-blockstates.patch b/patches/server/0413-Retain-block-place-order-when-capturing-blockstates.patch new file mode 100644 index 0000000000..8816366bcc --- /dev/null +++ b/patches/server/0413-Retain-block-place-order-when-capturing-blockstates.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Fri, 7 Aug 2020 04:27:56 -0700 +Subject: [PATCH] Retain block place order when capturing blockstates + +Fixes twisted vines not connecting properly when grown via +bonemeal by a player. + +In general, look at making this logic more robust (i.e properly handling +cases where a captured entry is overriden) - but for now this will do. + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 36d183d6b52185405f3dbf67d09bc21631e86870..2f82f77ba6530dcdb98037aa627ef3cead758b2e 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -154,7 +154,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + public boolean captureBlockStates = false; + public boolean captureTreeGeneration = false; + public Map capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper +- public Map capturedTileEntities = new HashMap<>(); ++ public Map capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates + public List captureDrops; + public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); + public boolean populating; diff --git a/patches/server/0413-Villager-resetOffers.patch b/patches/server/0413-Villager-resetOffers.patch deleted file mode 100644 index 1c9cac618a..0000000000 --- a/patches/server/0413-Villager-resetOffers.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 7 Oct 2019 00:15:37 -0500 -Subject: [PATCH] Villager#resetOffers - - -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 e5ce76abb09c91b881dee732c5985c53db552dfc..deac9d6389493213e2b0cc8e2b6ae0c9f055c011 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -@@ -114,6 +114,13 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa - return this.tradingPlayer != null; - } - -+ // Paper start - Villager#resetOffers -+ public void resetOffers() { -+ this.offers = new MerchantOffers(); -+ this.updateTrades(); -+ } -+ // Paper end - Villager#resetOffers -+ - @Override - public MerchantOffers getOffers() { - if (this.level().isClientSide) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java -index e5f733a765068b5640e811abf9fda945a9e91c7c..3199f04d00836a0a51547c679f3f3c80d00da502 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractVillager.java -@@ -34,4 +34,11 @@ public class CraftAbstractVillager extends CraftAgeable implements CraftMerchant - public Inventory getInventory() { - return new CraftInventory(this.getHandle().getInventory()); - } -+ -+ // Paper start - Villager#resetOffers -+ @Override -+ public void resetOffers() { -+ getHandle().resetOffers(); -+ } -+ // Paper end - Villager#resetOffers - } diff --git a/patches/server/0414-Fix-item-locations-dropped-from-campfires.patch b/patches/server/0414-Fix-item-locations-dropped-from-campfires.patch new file mode 100644 index 0000000000..df4949c1b8 --- /dev/null +++ b/patches/server/0414-Fix-item-locations-dropped-from-campfires.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 3 Oct 2020 20:32:25 -0500 +Subject: [PATCH] Fix item locations dropped from campfires + +Fixes #4259 by not flooring the blockposition among other weirdness +Vanilla Issue: MC-267622 + +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 0694b2a041c0012bbb7ab5c4c787c1e08db7757c..30035d534e144bf31f94073c57b0195be7e62772 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 +@@ -85,7 +85,14 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { + result = blockCookEvent.getResult(); + itemstack1 = CraftItemStack.asNMSCopy(result); + // CraftBukkit end +- Containers.dropItemStack(world, (double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), itemstack1); ++ // Paper start - Fix item locations dropped from campfires ++ double deviation = 0.05F * RandomSource.GAUSSIAN_SPREAD_FACTOR; ++ while (!itemstack1.isEmpty()) { ++ net.minecraft.world.entity.item.ItemEntity droppedItem = new net.minecraft.world.entity.item.ItemEntity(world, pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, itemstack1.split(world.random.nextInt(21) + 10)); ++ droppedItem.setDeltaMovement(world.random.triangle(0.0D, deviation), world.random.triangle(0.2D, deviation), world.random.triangle(0.0D, deviation)); ++ world.addFreshEntity(droppedItem); ++ } ++ // Paper end - Fix item locations dropped from campfires + blockEntity.items.set(i, ItemStack.EMPTY); + world.sendBlockUpdated(pos, state, state, 3); + world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state)); diff --git a/patches/server/0414-Retain-block-place-order-when-capturing-blockstates.patch b/patches/server/0414-Retain-block-place-order-when-capturing-blockstates.patch deleted file mode 100644 index 8816366bcc..0000000000 --- a/patches/server/0414-Retain-block-place-order-when-capturing-blockstates.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Fri, 7 Aug 2020 04:27:56 -0700 -Subject: [PATCH] Retain block place order when capturing blockstates - -Fixes twisted vines not connecting properly when grown via -bonemeal by a player. - -In general, look at making this logic more robust (i.e properly handling -cases where a captured entry is overriden) - but for now this will do. - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 36d183d6b52185405f3dbf67d09bc21631e86870..2f82f77ba6530dcdb98037aa627ef3cead758b2e 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -154,7 +154,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - public boolean captureBlockStates = false; - public boolean captureTreeGeneration = false; - public Map capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper -- public Map capturedTileEntities = new HashMap<>(); -+ public Map capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates - public List captureDrops; - public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); - public boolean populating; diff --git a/patches/server/0415-Fix-bell-block-entity-memory-leak.patch b/patches/server/0415-Fix-bell-block-entity-memory-leak.patch new file mode 100644 index 0000000000..5343b073cd --- /dev/null +++ b/patches/server/0415-Fix-bell-block-entity-memory-leak.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: giacomo <32515303+giacomozama@users.noreply.github.com> +Date: Sat, 10 Oct 2020 12:15:33 +0200 +Subject: [PATCH] Fix bell block entity memory leak + +BellBlockEntity has a list of entities (entitiesAtRing) that was not being cleared at the right time, causing leaks whenever a bell would be rung near a crowd of entities. + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java +index e1adfd10a2f67687b7123d20d31eb7d059a3e1e3..86dac3f82da065bf79d94da9df192f51ce4665e2 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java +@@ -63,6 +63,11 @@ public class BellBlockEntity extends BlockEntity { + + if (blockEntity.ticks >= 50) { + blockEntity.shaking = false; ++ // Paper start - Fix bell block entity memory leak ++ if (!blockEntity.resonating) { ++ blockEntity.nearbyEntities.clear(); ++ } ++ // Paper end - Fix bell block entity memory leak + blockEntity.ticks = 0; + } + +@@ -76,6 +81,7 @@ public class BellBlockEntity extends BlockEntity { + ++blockEntity.resonationTicks; + } else { + bellEffect.run(world, pos, blockEntity.nearbyEntities); ++ blockEntity.nearbyEntities.clear(); // Paper - Fix bell block entity memory leak + blockEntity.resonating = false; + } + } +@@ -125,6 +131,7 @@ public class BellBlockEntity extends BlockEntity { + } + } + ++ this.nearbyEntities.removeIf(e -> !e.isAlive()); // Paper - Fix bell block entity memory leak + } + + private static boolean areRaidersNearby(BlockPos pos, List hearingEntities) { diff --git a/patches/server/0415-Fix-item-locations-dropped-from-campfires.patch b/patches/server/0415-Fix-item-locations-dropped-from-campfires.patch deleted file mode 100644 index df4949c1b8..0000000000 --- a/patches/server/0415-Fix-item-locations-dropped-from-campfires.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 3 Oct 2020 20:32:25 -0500 -Subject: [PATCH] Fix item locations dropped from campfires - -Fixes #4259 by not flooring the blockposition among other weirdness -Vanilla Issue: MC-267622 - -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 0694b2a041c0012bbb7ab5c4c787c1e08db7757c..30035d534e144bf31f94073c57b0195be7e62772 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 -@@ -85,7 +85,14 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { - result = blockCookEvent.getResult(); - itemstack1 = CraftItemStack.asNMSCopy(result); - // CraftBukkit end -- Containers.dropItemStack(world, (double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), itemstack1); -+ // Paper start - Fix item locations dropped from campfires -+ double deviation = 0.05F * RandomSource.GAUSSIAN_SPREAD_FACTOR; -+ while (!itemstack1.isEmpty()) { -+ net.minecraft.world.entity.item.ItemEntity droppedItem = new net.minecraft.world.entity.item.ItemEntity(world, pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, itemstack1.split(world.random.nextInt(21) + 10)); -+ droppedItem.setDeltaMovement(world.random.triangle(0.0D, deviation), world.random.triangle(0.2D, deviation), world.random.triangle(0.0D, deviation)); -+ world.addFreshEntity(droppedItem); -+ } -+ // Paper end - Fix item locations dropped from campfires - blockEntity.items.set(i, ItemStack.EMPTY); - world.sendBlockUpdated(pos, state, state, 3); - world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state)); diff --git a/patches/server/0416-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch b/patches/server/0416-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch new file mode 100644 index 0000000000..8498d60497 --- /dev/null +++ b/patches/server/0416-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Toon Schoenmakers +Date: Fri, 23 Oct 2020 15:01:44 +0200 +Subject: [PATCH] Avoid error bubbling up when item stack is empty in fishing + loot + +This can realistically only happen if there's custom loot active on fishing +which can return 0 items. This would disconnect the player who's fishing. + +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 d0c7dc98ead5c9c52e9d24afe59874b8c512a165..966ba1a9c2e7923a970ce3799a5e2ef6ca36bf84 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java +@@ -511,9 +511,15 @@ public class FishingHook extends Projectile { + + while (iterator.hasNext()) { + ItemStack itemstack1 = (ItemStack) iterator.next(); +- ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack1); ++ // Paper start - new ItemEntity would throw if for whatever reason (mostly shitty datapacks) the itemstack1 turns out to be empty ++ // if the item stack is empty we instead just have our entityitem as null ++ ItemEntity entityitem = null; ++ if (!itemstack1.isEmpty()) { ++ entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack1); ++ } ++ // Paper end + // CraftBukkit start +- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), entityitem.getBukkitEntity(), (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_FISH); ++ 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.setExpToDrop(this.random.nextInt(6) + 1); + this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); + +@@ -526,8 +532,12 @@ public class FishingHook extends Projectile { + double d2 = entityhuman.getZ() - this.getZ(); + double d3 = 0.1D; + +- entityitem.setDeltaMovement(d0 * 0.1D, d1 * 0.1D + Math.sqrt(Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2)) * 0.08D, d2 * 0.1D); +- this.level().addFreshEntity(entityitem); ++ // Paper start - entity item can be null, so we need to check against this ++ if (entityitem != null) { ++ entityitem.setDeltaMovement(d0 * 0.1D, d1 * 0.1D + Math.sqrt(Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2)) * 0.08D, d2 * 0.1D); ++ this.level().addFreshEntity(entityitem); ++ } ++ // Paper end + // CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop() + if (playerFishEvent.getExpToDrop() > 0) { + entityhuman.level().addFreshEntity(new ExperienceOrb(entityhuman.level(), entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this)); // Paper diff --git a/patches/server/0416-Fix-bell-block-entity-memory-leak.patch b/patches/server/0416-Fix-bell-block-entity-memory-leak.patch deleted file mode 100644 index 5343b073cd..0000000000 --- a/patches/server/0416-Fix-bell-block-entity-memory-leak.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: giacomo <32515303+giacomozama@users.noreply.github.com> -Date: Sat, 10 Oct 2020 12:15:33 +0200 -Subject: [PATCH] Fix bell block entity memory leak - -BellBlockEntity has a list of entities (entitiesAtRing) that was not being cleared at the right time, causing leaks whenever a bell would be rung near a crowd of entities. - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java -index e1adfd10a2f67687b7123d20d31eb7d059a3e1e3..86dac3f82da065bf79d94da9df192f51ce4665e2 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java -@@ -63,6 +63,11 @@ public class BellBlockEntity extends BlockEntity { - - if (blockEntity.ticks >= 50) { - blockEntity.shaking = false; -+ // Paper start - Fix bell block entity memory leak -+ if (!blockEntity.resonating) { -+ blockEntity.nearbyEntities.clear(); -+ } -+ // Paper end - Fix bell block entity memory leak - blockEntity.ticks = 0; - } - -@@ -76,6 +81,7 @@ public class BellBlockEntity extends BlockEntity { - ++blockEntity.resonationTicks; - } else { - bellEffect.run(world, pos, blockEntity.nearbyEntities); -+ blockEntity.nearbyEntities.clear(); // Paper - Fix bell block entity memory leak - blockEntity.resonating = false; - } - } -@@ -125,6 +131,7 @@ public class BellBlockEntity extends BlockEntity { - } - } - -+ this.nearbyEntities.removeIf(e -> !e.isAlive()); // Paper - Fix bell block entity memory leak - } - - private static boolean areRaidersNearby(BlockPos pos, List hearingEntities) { diff --git a/patches/server/0417-Add-getOfflinePlayerIfCached-String.patch b/patches/server/0417-Add-getOfflinePlayerIfCached-String.patch new file mode 100644 index 0000000000..3b226a9a85 --- /dev/null +++ b/patches/server/0417-Add-getOfflinePlayerIfCached-String.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: oxygencraft <21054297+oxygencraft@users.noreply.github.com> +Date: Sun, 25 Oct 2020 18:34:50 +1100 +Subject: [PATCH] Add getOfflinePlayerIfCached(String) + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 9905555f249db72649bde8401835dd816ed7b428..f75d73402cf633254fe1ef4e919f09db48165190 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1968,6 +1968,28 @@ public final class CraftServer implements Server { + return result; + } + ++ // Paper start ++ @Override ++ @Nullable ++ public OfflinePlayer getOfflinePlayerIfCached(String name) { ++ Preconditions.checkArgument(name != null, "Name cannot be null"); ++ Preconditions.checkArgument(!name.isEmpty(), "Name cannot be empty"); ++ ++ OfflinePlayer result = getPlayerExact(name); ++ if (result == null) { ++ GameProfile profile = console.getProfileCache().getProfileIfCached(name); ++ ++ if (profile != null) { ++ result = getOfflinePlayer(profile); ++ } ++ } else { ++ offlinePlayers.remove(result.getUniqueId()); ++ } ++ ++ return result; ++ } ++ // Paper end ++ + @Override + public OfflinePlayer getOfflinePlayer(UUID id) { + Preconditions.checkArgument(id != null, "UUID id cannot be null"); diff --git a/patches/server/0417-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch b/patches/server/0417-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch deleted file mode 100644 index 8498d60497..0000000000 --- a/patches/server/0417-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Toon Schoenmakers -Date: Fri, 23 Oct 2020 15:01:44 +0200 -Subject: [PATCH] Avoid error bubbling up when item stack is empty in fishing - loot - -This can realistically only happen if there's custom loot active on fishing -which can return 0 items. This would disconnect the player who's fishing. - -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 d0c7dc98ead5c9c52e9d24afe59874b8c512a165..966ba1a9c2e7923a970ce3799a5e2ef6ca36bf84 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -@@ -511,9 +511,15 @@ public class FishingHook extends Projectile { - - while (iterator.hasNext()) { - ItemStack itemstack1 = (ItemStack) iterator.next(); -- ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack1); -+ // Paper start - new ItemEntity would throw if for whatever reason (mostly shitty datapacks) the itemstack1 turns out to be empty -+ // if the item stack is empty we instead just have our entityitem as null -+ ItemEntity entityitem = null; -+ if (!itemstack1.isEmpty()) { -+ entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack1); -+ } -+ // Paper end - // CraftBukkit start -- PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) entityhuman.getBukkitEntity(), entityitem.getBukkitEntity(), (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_FISH); -+ 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.setExpToDrop(this.random.nextInt(6) + 1); - this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); - -@@ -526,8 +532,12 @@ public class FishingHook extends Projectile { - double d2 = entityhuman.getZ() - this.getZ(); - double d3 = 0.1D; - -- entityitem.setDeltaMovement(d0 * 0.1D, d1 * 0.1D + Math.sqrt(Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2)) * 0.08D, d2 * 0.1D); -- this.level().addFreshEntity(entityitem); -+ // Paper start - entity item can be null, so we need to check against this -+ if (entityitem != null) { -+ entityitem.setDeltaMovement(d0 * 0.1D, d1 * 0.1D + Math.sqrt(Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2)) * 0.08D, d2 * 0.1D); -+ this.level().addFreshEntity(entityitem); -+ } -+ // Paper end - // CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop() - if (playerFishEvent.getExpToDrop() > 0) { - entityhuman.level().addFreshEntity(new ExperienceOrb(entityhuman.level(), entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this)); // Paper diff --git a/patches/server/0418-Add-getOfflinePlayerIfCached-String.patch b/patches/server/0418-Add-getOfflinePlayerIfCached-String.patch deleted file mode 100644 index 3b226a9a85..0000000000 --- a/patches/server/0418-Add-getOfflinePlayerIfCached-String.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: oxygencraft <21054297+oxygencraft@users.noreply.github.com> -Date: Sun, 25 Oct 2020 18:34:50 +1100 -Subject: [PATCH] Add getOfflinePlayerIfCached(String) - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 9905555f249db72649bde8401835dd816ed7b428..f75d73402cf633254fe1ef4e919f09db48165190 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1968,6 +1968,28 @@ public final class CraftServer implements Server { - return result; - } - -+ // Paper start -+ @Override -+ @Nullable -+ public OfflinePlayer getOfflinePlayerIfCached(String name) { -+ Preconditions.checkArgument(name != null, "Name cannot be null"); -+ Preconditions.checkArgument(!name.isEmpty(), "Name cannot be empty"); -+ -+ OfflinePlayer result = getPlayerExact(name); -+ if (result == null) { -+ GameProfile profile = console.getProfileCache().getProfileIfCached(name); -+ -+ if (profile != null) { -+ result = getOfflinePlayer(profile); -+ } -+ } else { -+ offlinePlayers.remove(result.getUniqueId()); -+ } -+ -+ return result; -+ } -+ // Paper end -+ - @Override - public OfflinePlayer getOfflinePlayer(UUID id) { - Preconditions.checkArgument(id != null, "UUID id cannot be null"); diff --git a/patches/server/0418-Add-ignore-discounts-API.patch b/patches/server/0418-Add-ignore-discounts-API.patch new file mode 100644 index 0000000000..a25e1bf557 --- /dev/null +++ b/patches/server/0418-Add-ignore-discounts-API.patch @@ -0,0 +1,150 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Mon, 9 Nov 2020 20:44:51 +0100 +Subject: [PATCH] Add ignore discounts API + + +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 77c8c09b3d74b0dd88321bdfdf19d0f089d4e432..27db2878073d1d77813574adfc54d1d686fc7088 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java +@@ -490,6 +490,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + + while (iterator.hasNext()) { + MerchantOffer merchantrecipe = (MerchantOffer) iterator.next(); ++ if (merchantrecipe.ignoreDiscounts) continue; // Paper - Add ignore discounts API + + merchantrecipe.addToSpecialPriceDiff(-Mth.floor((float) i * merchantrecipe.getPriceMultiplier())); + } +@@ -502,6 +503,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + + while (iterator1.hasNext()) { + MerchantOffer merchantrecipe1 = (MerchantOffer) iterator1.next(); ++ if (merchantrecipe1.ignoreDiscounts) continue; // Paper - Add ignore discounts API + double d0 = 0.3D + 0.0625D * (double) j; + int k = (int) Math.floor(d0 * (double) merchantrecipe1.getBaseCostA().getCount()); + +diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java +index 89982d25f60c8b60ba91e559ef88278f338fe215..0efc8d997b34302c3e0a5d7ec73a11a940dbeefe 100644 +--- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java ++++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java +@@ -33,6 +33,10 @@ public class MerchantOffer { + return merchantrecipe.priceMultiplier; + }), Codec.INT.lenientOptionalFieldOf("xp", 1).forGetter((merchantrecipe) -> { + return merchantrecipe.xp; ++ // Paper start ++ }), Codec.BOOL.lenientOptionalFieldOf("Paper.IgnoreDiscounts", false).forGetter((merchantrecipe) -> { ++ return merchantrecipe.ignoreDiscounts; ++ // Paper end + })).apply(instance, MerchantOffer::new); + }); + public static final StreamCodec STREAM_CODEC = StreamCodec.of(MerchantOffer::writeToStream, MerchantOffer::createFromStream); +@@ -46,6 +50,7 @@ public class MerchantOffer { + public int demand; + public float priceMultiplier; + public int xp; ++ public boolean ignoreDiscounts; // Paper - Add ignore discounts API + // CraftBukkit start + private CraftMerchantRecipe bukkitHandle; + +@@ -53,13 +58,14 @@ public class MerchantOffer { + return (this.bukkitHandle == null) ? this.bukkitHandle = new CraftMerchantRecipe(this) : this.bukkitHandle; + } + +- public MerchantOffer(ItemCost baseCostA, Optional costB, ItemStack result, int uses, int maxUses, int experience, float priceMultiplier, int demand, CraftMerchantRecipe bukkit) { ++ public MerchantOffer(ItemCost baseCostA, Optional costB, ItemStack result, int uses, int maxUses, int experience, float priceMultiplier, int demand, final boolean ignoreDiscounts, CraftMerchantRecipe bukkit) { // Paper + this(baseCostA, costB, result, uses, maxUses, experience, priceMultiplier, demand); ++ this.ignoreDiscounts = ignoreDiscounts; // Paper + this.bukkitHandle = bukkit; + } + // CraftBukkit end + +- private MerchantOffer(ItemCost firstBuyItem, Optional secondBuyItem, ItemStack sellItem, int uses, int maxUses, boolean rewardingPlayerExperience, int specialPrice, int demandBonus, float priceMultiplier, int merchantExperience) { ++ private MerchantOffer(ItemCost firstBuyItem, Optional secondBuyItem, ItemStack sellItem, int uses, int maxUses, boolean rewardingPlayerExperience, int specialPrice, int demandBonus, float priceMultiplier, int merchantExperience, final boolean ignoreDiscounts) { // Paper + this.baseCostA = firstBuyItem; + this.costB = secondBuyItem; + this.result = sellItem; +@@ -70,6 +76,7 @@ public class MerchantOffer { + this.demand = demandBonus; + this.priceMultiplier = priceMultiplier; + this.xp = merchantExperience; ++ this.ignoreDiscounts = ignoreDiscounts; // Paper + } + + public MerchantOffer(ItemCost buyItem, ItemStack sellItem, int maxUses, int merchantExperience, float priceMultiplier) { +@@ -85,11 +92,11 @@ public class MerchantOffer { + } + + public MerchantOffer(ItemCost firstBuyItem, Optional secondBuyItem, ItemStack sellItem, int uses, int maxUses, int merchantExperience, float priceMultiplier, int demandBonus) { +- this(firstBuyItem, secondBuyItem, sellItem, uses, maxUses, true, 0, demandBonus, priceMultiplier, merchantExperience); ++ this(firstBuyItem, secondBuyItem, sellItem, uses, maxUses, true, 0, demandBonus, priceMultiplier, merchantExperience, false); // Paper + } + + private MerchantOffer(MerchantOffer offer) { +- this(offer.baseCostA, offer.costB, offer.result.copy(), offer.uses, offer.maxUses, offer.rewardExp, offer.specialPriceDiff, offer.demand, offer.priceMultiplier, offer.xp); ++ this(offer.baseCostA, offer.costB, offer.result.copy(), offer.uses, offer.maxUses, offer.rewardExp, offer.specialPriceDiff, offer.demand, offer.priceMultiplier, offer.xp, offer.ignoreDiscounts); // Paper + } + + public ItemStack getBaseCostA() { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java +index bc1a92707c65474c1464d6f7c3a3265df6195228..e86cee25703a3c02ef62e302816253c360d557f3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java +@@ -24,11 +24,19 @@ public class CraftMerchantRecipe extends MerchantRecipe { + + @Deprecated + public CraftMerchantRecipe(ItemStack result, int uses, int maxUses, boolean experienceReward, int experience, float priceMultiplier) { +- this(result, uses, maxUses, experienceReward, experience, priceMultiplier, 0, 0); ++ // Paper start - add ignoreDiscounts param ++ this(result, uses, maxUses, experienceReward, experience, priceMultiplier, 0, 0, false); ++ } ++ public CraftMerchantRecipe(ItemStack result, int uses, int maxUses, boolean experienceReward, int experience, float priceMultiplier, boolean ignoreDiscounts) { ++ this(result, uses, maxUses, experienceReward, experience, priceMultiplier, 0, 0, ignoreDiscounts); + } + + public CraftMerchantRecipe(ItemStack result, int uses, int maxUses, boolean experienceReward, int experience, float priceMultiplier, int demand, int specialPrice) { +- super(result, uses, maxUses, experienceReward, experience, priceMultiplier, demand, specialPrice); ++ this(result, uses, maxUses, experienceReward, experience, priceMultiplier, demand, specialPrice, false); ++ } ++ public CraftMerchantRecipe(ItemStack result, int uses, int maxUses, boolean experienceReward, int experience, float priceMultiplier, int demand, int specialPrice, boolean ignoreDiscounts) { ++ super(result, uses, maxUses, experienceReward, experience, priceMultiplier, demand, specialPrice, ignoreDiscounts); ++ // Paper end + this.handle = new net.minecraft.world.item.trading.MerchantOffer( + new ItemCost(Items.AIR), + Optional.empty(), +@@ -38,6 +46,7 @@ public class CraftMerchantRecipe extends MerchantRecipe { + experience, + priceMultiplier, + demand, ++ ignoreDiscounts, // Paper - add ignoreDiscounts param + this + ); + this.setSpecialPrice(specialPrice); +@@ -114,6 +123,18 @@ public class CraftMerchantRecipe extends MerchantRecipe { + this.handle.priceMultiplier = priceMultiplier; + } + ++ // Paper start ++ @Override ++ public boolean shouldIgnoreDiscounts() { ++ return this.handle.ignoreDiscounts; ++ } ++ ++ @Override ++ public void setIgnoreDiscounts(boolean ignoreDiscounts) { ++ this.handle.ignoreDiscounts = ignoreDiscounts; ++ } ++ // Paper end ++ + public net.minecraft.world.item.trading.MerchantOffer toMinecraft() { + List ingredients = this.getIngredients(); + Preconditions.checkState(!ingredients.isEmpty(), "No offered ingredients"); +@@ -134,7 +155,7 @@ public class CraftMerchantRecipe extends MerchantRecipe { + if (recipe instanceof CraftMerchantRecipe) { + return (CraftMerchantRecipe) recipe; + } else { +- CraftMerchantRecipe craft = new CraftMerchantRecipe(recipe.getResult(), recipe.getUses(), recipe.getMaxUses(), recipe.hasExperienceReward(), recipe.getVillagerExperience(), recipe.getPriceMultiplier(), recipe.getDemand(), recipe.getSpecialPrice()); ++ CraftMerchantRecipe craft = new CraftMerchantRecipe(recipe.getResult(), recipe.getUses(), recipe.getMaxUses(), recipe.hasExperienceReward(), recipe.getVillagerExperience(), recipe.getPriceMultiplier(), recipe.getDemand(), recipe.getSpecialPrice(), recipe.shouldIgnoreDiscounts()); // Paper - shouldIgnoreDiscounts + craft.setIngredients(recipe.getIngredients()); + + return craft; diff --git a/patches/server/0419-Add-ignore-discounts-API.patch b/patches/server/0419-Add-ignore-discounts-API.patch deleted file mode 100644 index a25e1bf557..0000000000 --- a/patches/server/0419-Add-ignore-discounts-API.patch +++ /dev/null @@ -1,150 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Mon, 9 Nov 2020 20:44:51 +0100 -Subject: [PATCH] Add ignore discounts API - - -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 77c8c09b3d74b0dd88321bdfdf19d0f089d4e432..27db2878073d1d77813574adfc54d1d686fc7088 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -490,6 +490,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - - while (iterator.hasNext()) { - MerchantOffer merchantrecipe = (MerchantOffer) iterator.next(); -+ if (merchantrecipe.ignoreDiscounts) continue; // Paper - Add ignore discounts API - - merchantrecipe.addToSpecialPriceDiff(-Mth.floor((float) i * merchantrecipe.getPriceMultiplier())); - } -@@ -502,6 +503,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - - while (iterator1.hasNext()) { - MerchantOffer merchantrecipe1 = (MerchantOffer) iterator1.next(); -+ if (merchantrecipe1.ignoreDiscounts) continue; // Paper - Add ignore discounts API - double d0 = 0.3D + 0.0625D * (double) j; - int k = (int) Math.floor(d0 * (double) merchantrecipe1.getBaseCostA().getCount()); - -diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -index 89982d25f60c8b60ba91e559ef88278f338fe215..0efc8d997b34302c3e0a5d7ec73a11a940dbeefe 100644 ---- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -+++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -@@ -33,6 +33,10 @@ public class MerchantOffer { - return merchantrecipe.priceMultiplier; - }), Codec.INT.lenientOptionalFieldOf("xp", 1).forGetter((merchantrecipe) -> { - return merchantrecipe.xp; -+ // Paper start -+ }), Codec.BOOL.lenientOptionalFieldOf("Paper.IgnoreDiscounts", false).forGetter((merchantrecipe) -> { -+ return merchantrecipe.ignoreDiscounts; -+ // Paper end - })).apply(instance, MerchantOffer::new); - }); - public static final StreamCodec STREAM_CODEC = StreamCodec.of(MerchantOffer::writeToStream, MerchantOffer::createFromStream); -@@ -46,6 +50,7 @@ public class MerchantOffer { - public int demand; - public float priceMultiplier; - public int xp; -+ public boolean ignoreDiscounts; // Paper - Add ignore discounts API - // CraftBukkit start - private CraftMerchantRecipe bukkitHandle; - -@@ -53,13 +58,14 @@ public class MerchantOffer { - return (this.bukkitHandle == null) ? this.bukkitHandle = new CraftMerchantRecipe(this) : this.bukkitHandle; - } - -- public MerchantOffer(ItemCost baseCostA, Optional costB, ItemStack result, int uses, int maxUses, int experience, float priceMultiplier, int demand, CraftMerchantRecipe bukkit) { -+ public MerchantOffer(ItemCost baseCostA, Optional costB, ItemStack result, int uses, int maxUses, int experience, float priceMultiplier, int demand, final boolean ignoreDiscounts, CraftMerchantRecipe bukkit) { // Paper - this(baseCostA, costB, result, uses, maxUses, experience, priceMultiplier, demand); -+ this.ignoreDiscounts = ignoreDiscounts; // Paper - this.bukkitHandle = bukkit; - } - // CraftBukkit end - -- private MerchantOffer(ItemCost firstBuyItem, Optional secondBuyItem, ItemStack sellItem, int uses, int maxUses, boolean rewardingPlayerExperience, int specialPrice, int demandBonus, float priceMultiplier, int merchantExperience) { -+ private MerchantOffer(ItemCost firstBuyItem, Optional secondBuyItem, ItemStack sellItem, int uses, int maxUses, boolean rewardingPlayerExperience, int specialPrice, int demandBonus, float priceMultiplier, int merchantExperience, final boolean ignoreDiscounts) { // Paper - this.baseCostA = firstBuyItem; - this.costB = secondBuyItem; - this.result = sellItem; -@@ -70,6 +76,7 @@ public class MerchantOffer { - this.demand = demandBonus; - this.priceMultiplier = priceMultiplier; - this.xp = merchantExperience; -+ this.ignoreDiscounts = ignoreDiscounts; // Paper - } - - public MerchantOffer(ItemCost buyItem, ItemStack sellItem, int maxUses, int merchantExperience, float priceMultiplier) { -@@ -85,11 +92,11 @@ public class MerchantOffer { - } - - public MerchantOffer(ItemCost firstBuyItem, Optional secondBuyItem, ItemStack sellItem, int uses, int maxUses, int merchantExperience, float priceMultiplier, int demandBonus) { -- this(firstBuyItem, secondBuyItem, sellItem, uses, maxUses, true, 0, demandBonus, priceMultiplier, merchantExperience); -+ this(firstBuyItem, secondBuyItem, sellItem, uses, maxUses, true, 0, demandBonus, priceMultiplier, merchantExperience, false); // Paper - } - - private MerchantOffer(MerchantOffer offer) { -- this(offer.baseCostA, offer.costB, offer.result.copy(), offer.uses, offer.maxUses, offer.rewardExp, offer.specialPriceDiff, offer.demand, offer.priceMultiplier, offer.xp); -+ this(offer.baseCostA, offer.costB, offer.result.copy(), offer.uses, offer.maxUses, offer.rewardExp, offer.specialPriceDiff, offer.demand, offer.priceMultiplier, offer.xp, offer.ignoreDiscounts); // Paper - } - - public ItemStack getBaseCostA() { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java -index bc1a92707c65474c1464d6f7c3a3265df6195228..e86cee25703a3c02ef62e302816253c360d557f3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java -@@ -24,11 +24,19 @@ public class CraftMerchantRecipe extends MerchantRecipe { - - @Deprecated - public CraftMerchantRecipe(ItemStack result, int uses, int maxUses, boolean experienceReward, int experience, float priceMultiplier) { -- this(result, uses, maxUses, experienceReward, experience, priceMultiplier, 0, 0); -+ // Paper start - add ignoreDiscounts param -+ this(result, uses, maxUses, experienceReward, experience, priceMultiplier, 0, 0, false); -+ } -+ public CraftMerchantRecipe(ItemStack result, int uses, int maxUses, boolean experienceReward, int experience, float priceMultiplier, boolean ignoreDiscounts) { -+ this(result, uses, maxUses, experienceReward, experience, priceMultiplier, 0, 0, ignoreDiscounts); - } - - public CraftMerchantRecipe(ItemStack result, int uses, int maxUses, boolean experienceReward, int experience, float priceMultiplier, int demand, int specialPrice) { -- super(result, uses, maxUses, experienceReward, experience, priceMultiplier, demand, specialPrice); -+ this(result, uses, maxUses, experienceReward, experience, priceMultiplier, demand, specialPrice, false); -+ } -+ public CraftMerchantRecipe(ItemStack result, int uses, int maxUses, boolean experienceReward, int experience, float priceMultiplier, int demand, int specialPrice, boolean ignoreDiscounts) { -+ super(result, uses, maxUses, experienceReward, experience, priceMultiplier, demand, specialPrice, ignoreDiscounts); -+ // Paper end - this.handle = new net.minecraft.world.item.trading.MerchantOffer( - new ItemCost(Items.AIR), - Optional.empty(), -@@ -38,6 +46,7 @@ public class CraftMerchantRecipe extends MerchantRecipe { - experience, - priceMultiplier, - demand, -+ ignoreDiscounts, // Paper - add ignoreDiscounts param - this - ); - this.setSpecialPrice(specialPrice); -@@ -114,6 +123,18 @@ public class CraftMerchantRecipe extends MerchantRecipe { - this.handle.priceMultiplier = priceMultiplier; - } - -+ // Paper start -+ @Override -+ public boolean shouldIgnoreDiscounts() { -+ return this.handle.ignoreDiscounts; -+ } -+ -+ @Override -+ public void setIgnoreDiscounts(boolean ignoreDiscounts) { -+ this.handle.ignoreDiscounts = ignoreDiscounts; -+ } -+ // Paper end -+ - public net.minecraft.world.item.trading.MerchantOffer toMinecraft() { - List ingredients = this.getIngredients(); - Preconditions.checkState(!ingredients.isEmpty(), "No offered ingredients"); -@@ -134,7 +155,7 @@ public class CraftMerchantRecipe extends MerchantRecipe { - if (recipe instanceof CraftMerchantRecipe) { - return (CraftMerchantRecipe) recipe; - } else { -- CraftMerchantRecipe craft = new CraftMerchantRecipe(recipe.getResult(), recipe.getUses(), recipe.getMaxUses(), recipe.hasExperienceReward(), recipe.getVillagerExperience(), recipe.getPriceMultiplier(), recipe.getDemand(), recipe.getSpecialPrice()); -+ CraftMerchantRecipe craft = new CraftMerchantRecipe(recipe.getResult(), recipe.getUses(), recipe.getMaxUses(), recipe.hasExperienceReward(), recipe.getVillagerExperience(), recipe.getPriceMultiplier(), recipe.getDemand(), recipe.getSpecialPrice(), recipe.shouldIgnoreDiscounts()); // Paper - shouldIgnoreDiscounts - craft.setIngredients(recipe.getIngredients()); - - return craft; diff --git a/patches/server/0419-Toggle-for-removing-existing-dragon.patch b/patches/server/0419-Toggle-for-removing-existing-dragon.patch new file mode 100644 index 0000000000..5efff5ff3f --- /dev/null +++ b/patches/server/0419-Toggle-for-removing-existing-dragon.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Wed, 30 Sep 2020 22:49:14 +0200 +Subject: [PATCH] Toggle for removing existing dragon + + +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 0f34a5ce0352f627099a719b78e530e5e572581a..323fbf684b7062c1b9084f1718538a3b3414d5bf 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 +@@ -212,7 +212,7 @@ public class EndDragonFight { + this.dragonUUID = entityenderdragon.getUUID(); + EndDragonFight.LOGGER.info("Found that there's a dragon still alive ({})", entityenderdragon); + this.dragonKilled = false; +- if (!flag) { ++ if (!flag && this.level.paperConfig().entities.behavior.shouldRemoveDragon) { // Paper - Toggle for removing existing dragon + EndDragonFight.LOGGER.info("But we didn't have a portal, let's remove it."); + entityenderdragon.discard(null); // CraftBukkit - add Bukkit remove cause + this.dragonUUID = null; diff --git a/patches/server/0420-Fix-client-lag-on-advancement-loading.patch b/patches/server/0420-Fix-client-lag-on-advancement-loading.patch new file mode 100644 index 0000000000..4866bbae4b --- /dev/null +++ b/patches/server/0420-Fix-client-lag-on-advancement-loading.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Sat, 31 Oct 2020 11:49:01 -0700 +Subject: [PATCH] Fix client lag on advancement loading + +When new advancements are added via the UnsafeValues#loadAdvancement +API, it triggers a full datapack reload when this is not necessary. The +advancement is already loaded directly into the advancement registry, +and the point of saving the advancement to the Bukkit datapack seems to +be for persistence. By removing the call to reload datapacks when an +advancement is loaded, the client no longer completely freezes up when +adding a new advancement. +To ensure the client still receives the updated advancement data, we +manually reload the advancement data for all players, which +normally takes place as a part of the datapack reloading. + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 78bc460fff7d537109883f1469500f6f536c598e..5f0fd1d4fe419435ac7293106c0ebb5382d64074 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -318,7 +318,13 @@ public final class CraftMagicNumbers implements UnsafeValues { + Bukkit.getLogger().log(Level.SEVERE, "Error saving advancement " + key, ex); + } + +- MinecraftServer.getServer().getPlayerList().reloadResources(); ++ // Paper start - Fix client lag on advancement loading ++ //MinecraftServer.getServer().getPlayerList().reload(); ++ MinecraftServer.getServer().getPlayerList().getPlayers().forEach(player -> { ++ player.getAdvancements().reload(MinecraftServer.getServer().getAdvancements()); ++ player.getAdvancements().flushDirty(player); ++ }); ++ // Paper end - Fix client lag on advancement loading + + return bukkit; + } diff --git a/patches/server/0420-Toggle-for-removing-existing-dragon.patch b/patches/server/0420-Toggle-for-removing-existing-dragon.patch deleted file mode 100644 index 5efff5ff3f..0000000000 --- a/patches/server/0420-Toggle-for-removing-existing-dragon.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Wed, 30 Sep 2020 22:49:14 +0200 -Subject: [PATCH] Toggle for removing existing dragon - - -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 0f34a5ce0352f627099a719b78e530e5e572581a..323fbf684b7062c1b9084f1718538a3b3414d5bf 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 -@@ -212,7 +212,7 @@ public class EndDragonFight { - this.dragonUUID = entityenderdragon.getUUID(); - EndDragonFight.LOGGER.info("Found that there's a dragon still alive ({})", entityenderdragon); - this.dragonKilled = false; -- if (!flag) { -+ if (!flag && this.level.paperConfig().entities.behavior.shouldRemoveDragon) { // Paper - Toggle for removing existing dragon - EndDragonFight.LOGGER.info("But we didn't have a portal, let's remove it."); - entityenderdragon.discard(null); // CraftBukkit - add Bukkit remove cause - this.dragonUUID = null; diff --git a/patches/server/0421-Fix-client-lag-on-advancement-loading.patch b/patches/server/0421-Fix-client-lag-on-advancement-loading.patch deleted file mode 100644 index 4866bbae4b..0000000000 --- a/patches/server/0421-Fix-client-lag-on-advancement-loading.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sat, 31 Oct 2020 11:49:01 -0700 -Subject: [PATCH] Fix client lag on advancement loading - -When new advancements are added via the UnsafeValues#loadAdvancement -API, it triggers a full datapack reload when this is not necessary. The -advancement is already loaded directly into the advancement registry, -and the point of saving the advancement to the Bukkit datapack seems to -be for persistence. By removing the call to reload datapacks when an -advancement is loaded, the client no longer completely freezes up when -adding a new advancement. -To ensure the client still receives the updated advancement data, we -manually reload the advancement data for all players, which -normally takes place as a part of the datapack reloading. - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 78bc460fff7d537109883f1469500f6f536c598e..5f0fd1d4fe419435ac7293106c0ebb5382d64074 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -318,7 +318,13 @@ public final class CraftMagicNumbers implements UnsafeValues { - Bukkit.getLogger().log(Level.SEVERE, "Error saving advancement " + key, ex); - } - -- MinecraftServer.getServer().getPlayerList().reloadResources(); -+ // Paper start - Fix client lag on advancement loading -+ //MinecraftServer.getServer().getPlayerList().reload(); -+ MinecraftServer.getServer().getPlayerList().getPlayers().forEach(player -> { -+ player.getAdvancements().reload(MinecraftServer.getServer().getAdvancements()); -+ player.getAdvancements().flushDirty(player); -+ }); -+ // Paper end - Fix client lag on advancement loading - - return bukkit; - } diff --git a/patches/server/0421-Item-no-age-no-player-pickup.patch b/patches/server/0421-Item-no-age-no-player-pickup.patch new file mode 100644 index 0000000000..1fffbaf558 --- /dev/null +++ b/patches/server/0421-Item-no-age-no-player-pickup.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alfie Smith +Date: Sat, 7 Nov 2020 01:20:33 +0000 +Subject: [PATCH] Item no age & no player pickup + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +index 5620a0849fda49313c68edfd747fedd09641a3d5..4a15c3786edbfeae3367c0b20fb6aee11d62aea6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +@@ -9,6 +9,11 @@ import org.bukkit.inventory.ItemStack; + + public class CraftItem extends CraftEntity implements Item { + ++ // Paper start ++ private final static int NO_AGE_TIME = (int) Short.MIN_VALUE; ++ private final static int NO_PICKUP_TIME = (int) Short.MAX_VALUE; ++ // Paper end ++ + public CraftItem(CraftServer server, ItemEntity entity) { + super(server, entity); + } +@@ -73,6 +78,26 @@ public class CraftItem extends CraftEntity implements Item { + public void setCanMobPickup(boolean canMobPickup) { + this.getHandle().canMobPickup = canMobPickup; + } ++ ++ @Override ++ public boolean canPlayerPickup() { ++ return this.getHandle().pickupDelay != NO_PICKUP_TIME; ++ } ++ ++ @Override ++ public void setCanPlayerPickup(boolean canPlayerPickup) { ++ this.getHandle().pickupDelay = canPlayerPickup ? 0 : NO_PICKUP_TIME; ++ } ++ ++ @Override ++ public boolean willAge() { ++ return this.getHandle().age != NO_AGE_TIME; ++ } ++ ++ @Override ++ public void setWillAge(boolean willAge) { ++ this.getHandle().age = willAge ? 0 : NO_AGE_TIME; ++ } + // Paper end + + @Override diff --git a/patches/server/0422-Beacon-API-custom-effect-ranges.patch b/patches/server/0422-Beacon-API-custom-effect-ranges.patch new file mode 100644 index 0000000000..6afe0e8f7c --- /dev/null +++ b/patches/server/0422-Beacon-API-custom-effect-ranges.patch @@ -0,0 +1,131 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 24 Jun 2020 12:39:08 -0600 +Subject: [PATCH] Beacon API - custom effect ranges + + +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 8332296663b845df1d09d403b49a4769b2d54afc..dc3171b1493d7c4c8ddf1c79587c4e27bd819c17 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 +@@ -86,6 +86,26 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + return (BeaconBlockEntity.hasSecondaryEffect(this.levels, this.primaryPower, this.secondaryPower)) ? CraftPotionUtil.toBukkit(new MobEffectInstance(this.secondaryPower, BeaconBlockEntity.getLevel(this.levels), BeaconBlockEntity.getAmplification(this.levels, this.primaryPower, this.secondaryPower), true, true)) : null; + } + // CraftBukkit end ++ // Paper start - Custom beacon ranges ++ private final String PAPER_RANGE_TAG = "Paper.Range"; ++ private double effectRange = -1; ++ ++ public double getEffectRange() { ++ if (this.effectRange < 0) { ++ return this.levels * 10 + 10; ++ } else { ++ return effectRange; ++ } ++ } ++ ++ public void setEffectRange(double range) { ++ this.effectRange = range; ++ } ++ ++ public void resetEffectRange() { ++ this.effectRange = -1; ++ } ++ // Paper end - Custom beacon ranges + + @Nullable + static Holder filterEffect(@Nullable Holder effect) { +@@ -201,7 +221,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + } + + if (blockEntity.levels > 0 && !blockEntity.beamSections.isEmpty()) { +- BeaconBlockEntity.applyEffects(world, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower); ++ BeaconBlockEntity.applyEffects(world, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower, blockEntity); // Paper - Custom beacon ranges + BeaconBlockEntity.playSound(world, pos, SoundEvents.BEACON_AMBIENT); + } + } +@@ -287,8 +307,13 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + } + + public static List getHumansInRange(Level world, BlockPos blockposition, int i) { ++ // Paper start - Custom beacon ranges ++ return BeaconBlockEntity.getHumansInRange(world, blockposition, i, null); ++ } ++ public static List getHumansInRange(Level world, BlockPos blockposition, int i, @Nullable BeaconBlockEntity blockEntity) { ++ // Paper end - Custom beacon ranges + { +- double d0 = (double) (i * 10 + 10); ++ 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); +@@ -329,12 +354,17 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + } + + private static void applyEffects(Level world, BlockPos pos, int beaconLevel, @Nullable Holder primaryEffect, @Nullable Holder secondaryEffect) { ++ // Paper start - Custom beacon ranges ++ BeaconBlockEntity.applyEffects(world, pos, beaconLevel, primaryEffect, secondaryEffect, null); ++ } ++ private static void applyEffects(Level world, BlockPos pos, int beaconLevel, @Nullable Holder primaryEffect, @Nullable Holder secondaryEffect, @Nullable BeaconBlockEntity blockEntity) { ++ // Paper end - Custom beacon ranges + if (!world.isClientSide && primaryEffect != null) { + double d0 = (double) (beaconLevel * 10 + 10); + byte b0 = BeaconBlockEntity.getAmplification(beaconLevel, primaryEffect, secondaryEffect); + + int j = BeaconBlockEntity.getLevel(beaconLevel); +- List list = BeaconBlockEntity.getHumansInRange(world, pos, beaconLevel); ++ List list = BeaconBlockEntity.getHumansInRange(world, pos, beaconLevel, blockEntity); // Paper - Custom beacon ranges + + BeaconBlockEntity.applyEffect(list, primaryEffect, j, b0, true, pos); // Paper - BeaconEffectEvent + +@@ -395,6 +425,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + } + + this.lockKey = LockCode.fromTag(nbt, registries); ++ this.effectRange = nbt.contains(PAPER_RANGE_TAG, 6) ? nbt.getDouble(PAPER_RANGE_TAG) : -1; // Paper - Custom beacon ranges + } + + @Override +@@ -408,6 +439,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + } + + this.lockKey.addToTag(nbt, registries); ++ nbt.putDouble(PAPER_RANGE_TAG, this.effectRange); // Paper - Custom beacon ranges + } + + public void setCustomName(@Nullable Component customName) { +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java +index 8021ac39cb9c1ff45123d51e6f13b840d1290bb2..275d4f9e07ff7383b18238071e067b7f44483ece 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java +@@ -42,7 +42,7 @@ public class CraftBeacon extends CraftBlockEntityState implem + if (tileEntity instanceof BeaconBlockEntity) { + BeaconBlockEntity beacon = (BeaconBlockEntity) tileEntity; + +- Collection nms = BeaconBlockEntity.getHumansInRange(beacon.getLevel(), beacon.getBlockPos(), beacon.levels); ++ Collection nms = BeaconBlockEntity.getHumansInRange(beacon.getLevel(), beacon.getBlockPos(), beacon.levels, beacon); // Paper - Custom beacon ranges + Collection bukkit = new ArrayList(nms.size()); + + for (Player human : nms) { +@@ -145,4 +145,21 @@ public class CraftBeacon extends CraftBlockEntityState implem + public CraftBeacon copy(Location location) { + return new CraftBeacon(this, location); + } ++ ++ // Paper start ++ @Override ++ public double getEffectRange() { ++ return this.getSnapshot().getEffectRange(); ++ } ++ ++ @Override ++ public void setEffectRange(double range) { ++ this.getSnapshot().setEffectRange(range); ++ } ++ ++ @Override ++ public void resetEffectRange() { ++ this.getSnapshot().resetEffectRange(); ++ } ++ // Paper end + } diff --git a/patches/server/0422-Item-no-age-no-player-pickup.patch b/patches/server/0422-Item-no-age-no-player-pickup.patch deleted file mode 100644 index 1fffbaf558..0000000000 --- a/patches/server/0422-Item-no-age-no-player-pickup.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Alfie Smith -Date: Sat, 7 Nov 2020 01:20:33 +0000 -Subject: [PATCH] Item no age & no player pickup - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -index 5620a0849fda49313c68edfd747fedd09641a3d5..4a15c3786edbfeae3367c0b20fb6aee11d62aea6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -@@ -9,6 +9,11 @@ import org.bukkit.inventory.ItemStack; - - public class CraftItem extends CraftEntity implements Item { - -+ // Paper start -+ private final static int NO_AGE_TIME = (int) Short.MIN_VALUE; -+ private final static int NO_PICKUP_TIME = (int) Short.MAX_VALUE; -+ // Paper end -+ - public CraftItem(CraftServer server, ItemEntity entity) { - super(server, entity); - } -@@ -73,6 +78,26 @@ public class CraftItem extends CraftEntity implements Item { - public void setCanMobPickup(boolean canMobPickup) { - this.getHandle().canMobPickup = canMobPickup; - } -+ -+ @Override -+ public boolean canPlayerPickup() { -+ return this.getHandle().pickupDelay != NO_PICKUP_TIME; -+ } -+ -+ @Override -+ public void setCanPlayerPickup(boolean canPlayerPickup) { -+ this.getHandle().pickupDelay = canPlayerPickup ? 0 : NO_PICKUP_TIME; -+ } -+ -+ @Override -+ public boolean willAge() { -+ return this.getHandle().age != NO_AGE_TIME; -+ } -+ -+ @Override -+ public void setWillAge(boolean willAge) { -+ this.getHandle().age = willAge ? 0 : NO_AGE_TIME; -+ } - // Paper end - - @Override diff --git a/patches/server/0423-Add-API-for-quit-reason.patch b/patches/server/0423-Add-API-for-quit-reason.patch new file mode 100644 index 0000000000..954d1e73be --- /dev/null +++ b/patches/server/0423-Add-API-for-quit-reason.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 14 Nov 2020 16:19:52 +0100 +Subject: [PATCH] Add API for quit reason + + +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index f9158826f16e45c81714c2e0a284828bc5bb95c8..448bde861b4190a678a8ccb63cade43c4a3d6ad9 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -167,8 +167,10 @@ public class Connection extends SimpleChannelInboundHandler> { + + this.handlingFault = true; + if (this.channel.isOpen()) { ++ net.minecraft.server.level.ServerPlayer player = this.getPlayer(); // Paper - Add API for quit reason + if (throwable instanceof TimeoutException) { + Connection.LOGGER.debug("Timeout", throwable); ++ if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.TIMED_OUT; // Paper - Add API for quit reason + this.disconnect((Component) Component.translatable("disconnect.timeout")); + } else { + MutableComponent ichatmutablecomponent = Component.translatable("disconnect.genericReason", "Internal Exception: " + String.valueOf(throwable)); +@@ -181,6 +183,7 @@ public class Connection extends SimpleChannelInboundHandler> { + disconnectiondetails = new DisconnectionDetails(ichatmutablecomponent); + } + ++ if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.ERRONEOUS_STATE; // Paper - Add API for quit reason + if (flag) { + Connection.LOGGER.debug("Failed to sent packet", throwable); + if (this.getSending() == PacketFlow.CLIENTBOUND) { +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index ed2164d8c652b135f9cb777f1a6242bcfec36bbc..1dfc696ff2e122c6c61fdd1c7c5761ae81fa75ec 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -321,6 +321,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + public boolean isRealPlayer; // Paper + public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent + public @Nullable String clientBrandName = null; // Paper - Brand support ++ public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event + + public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { + super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); +diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +index 9a8b08d4b70b8890961e4af7ce6e870aa1c7c810..f8ae8c8eff73e4e87eb34d0f2635517f1688a6f1 100644 +--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +@@ -383,6 +383,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + + private void disconnect0(DisconnectionDetails disconnectiondetails) { + // CraftBukkit end ++ this.player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.KICKED; // Paper - Add API for quit reason + this.connection.send(new ClientboundDisconnectPacket(disconnectiondetails.reason()), PacketSendListener.thenRun(() -> { + this.connection.disconnect(disconnectiondetails); + })); +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index f11bea4618757ac8060098ab7a7a2642ff0a1ae4..e734798640cc016d54c56b7870a1a653353ff709 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -519,7 +519,7 @@ public abstract class PlayerList { + entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper - Inventory close reason + } + +- PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName()))); // Paper - Adventure ++ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName())), entityplayer.quitReason); // Paper - Adventure & Add API for quit reason + this.cserver.getPluginManager().callEvent(playerQuitEvent); + entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); + diff --git a/patches/server/0423-Beacon-API-custom-effect-ranges.patch b/patches/server/0423-Beacon-API-custom-effect-ranges.patch deleted file mode 100644 index 6afe0e8f7c..0000000000 --- a/patches/server/0423-Beacon-API-custom-effect-ranges.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 24 Jun 2020 12:39:08 -0600 -Subject: [PATCH] Beacon API - custom effect ranges - - -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 8332296663b845df1d09d403b49a4769b2d54afc..dc3171b1493d7c4c8ddf1c79587c4e27bd819c17 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 -@@ -86,6 +86,26 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - return (BeaconBlockEntity.hasSecondaryEffect(this.levels, this.primaryPower, this.secondaryPower)) ? CraftPotionUtil.toBukkit(new MobEffectInstance(this.secondaryPower, BeaconBlockEntity.getLevel(this.levels), BeaconBlockEntity.getAmplification(this.levels, this.primaryPower, this.secondaryPower), true, true)) : null; - } - // CraftBukkit end -+ // Paper start - Custom beacon ranges -+ private final String PAPER_RANGE_TAG = "Paper.Range"; -+ private double effectRange = -1; -+ -+ public double getEffectRange() { -+ if (this.effectRange < 0) { -+ return this.levels * 10 + 10; -+ } else { -+ return effectRange; -+ } -+ } -+ -+ public void setEffectRange(double range) { -+ this.effectRange = range; -+ } -+ -+ public void resetEffectRange() { -+ this.effectRange = -1; -+ } -+ // Paper end - Custom beacon ranges - - @Nullable - static Holder filterEffect(@Nullable Holder effect) { -@@ -201,7 +221,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - } - - if (blockEntity.levels > 0 && !blockEntity.beamSections.isEmpty()) { -- BeaconBlockEntity.applyEffects(world, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower); -+ BeaconBlockEntity.applyEffects(world, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower, blockEntity); // Paper - Custom beacon ranges - BeaconBlockEntity.playSound(world, pos, SoundEvents.BEACON_AMBIENT); - } - } -@@ -287,8 +307,13 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - } - - public static List getHumansInRange(Level world, BlockPos blockposition, int i) { -+ // Paper start - Custom beacon ranges -+ return BeaconBlockEntity.getHumansInRange(world, blockposition, i, null); -+ } -+ public static List getHumansInRange(Level world, BlockPos blockposition, int i, @Nullable BeaconBlockEntity blockEntity) { -+ // Paper end - Custom beacon ranges - { -- double d0 = (double) (i * 10 + 10); -+ 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); -@@ -329,12 +354,17 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - } - - private static void applyEffects(Level world, BlockPos pos, int beaconLevel, @Nullable Holder primaryEffect, @Nullable Holder secondaryEffect) { -+ // Paper start - Custom beacon ranges -+ BeaconBlockEntity.applyEffects(world, pos, beaconLevel, primaryEffect, secondaryEffect, null); -+ } -+ private static void applyEffects(Level world, BlockPos pos, int beaconLevel, @Nullable Holder primaryEffect, @Nullable Holder secondaryEffect, @Nullable BeaconBlockEntity blockEntity) { -+ // Paper end - Custom beacon ranges - if (!world.isClientSide && primaryEffect != null) { - double d0 = (double) (beaconLevel * 10 + 10); - byte b0 = BeaconBlockEntity.getAmplification(beaconLevel, primaryEffect, secondaryEffect); - - int j = BeaconBlockEntity.getLevel(beaconLevel); -- List list = BeaconBlockEntity.getHumansInRange(world, pos, beaconLevel); -+ List list = BeaconBlockEntity.getHumansInRange(world, pos, beaconLevel, blockEntity); // Paper - Custom beacon ranges - - BeaconBlockEntity.applyEffect(list, primaryEffect, j, b0, true, pos); // Paper - BeaconEffectEvent - -@@ -395,6 +425,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - } - - this.lockKey = LockCode.fromTag(nbt, registries); -+ this.effectRange = nbt.contains(PAPER_RANGE_TAG, 6) ? nbt.getDouble(PAPER_RANGE_TAG) : -1; // Paper - Custom beacon ranges - } - - @Override -@@ -408,6 +439,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - } - - this.lockKey.addToTag(nbt, registries); -+ nbt.putDouble(PAPER_RANGE_TAG, this.effectRange); // Paper - Custom beacon ranges - } - - public void setCustomName(@Nullable Component customName) { -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java -index 8021ac39cb9c1ff45123d51e6f13b840d1290bb2..275d4f9e07ff7383b18238071e067b7f44483ece 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java -@@ -42,7 +42,7 @@ public class CraftBeacon extends CraftBlockEntityState implem - if (tileEntity instanceof BeaconBlockEntity) { - BeaconBlockEntity beacon = (BeaconBlockEntity) tileEntity; - -- Collection nms = BeaconBlockEntity.getHumansInRange(beacon.getLevel(), beacon.getBlockPos(), beacon.levels); -+ Collection nms = BeaconBlockEntity.getHumansInRange(beacon.getLevel(), beacon.getBlockPos(), beacon.levels, beacon); // Paper - Custom beacon ranges - Collection bukkit = new ArrayList(nms.size()); - - for (Player human : nms) { -@@ -145,4 +145,21 @@ public class CraftBeacon extends CraftBlockEntityState implem - public CraftBeacon copy(Location location) { - return new CraftBeacon(this, location); - } -+ -+ // Paper start -+ @Override -+ public double getEffectRange() { -+ return this.getSnapshot().getEffectRange(); -+ } -+ -+ @Override -+ public void setEffectRange(double range) { -+ this.getSnapshot().setEffectRange(range); -+ } -+ -+ @Override -+ public void resetEffectRange() { -+ this.getSnapshot().resetEffectRange(); -+ } -+ // Paper end - } diff --git a/patches/server/0424-Add-API-for-quit-reason.patch b/patches/server/0424-Add-API-for-quit-reason.patch deleted file mode 100644 index ef6e4a94d3..0000000000 --- a/patches/server/0424-Add-API-for-quit-reason.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 14 Nov 2020 16:19:52 +0100 -Subject: [PATCH] Add API for quit reason - - -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index f9158826f16e45c81714c2e0a284828bc5bb95c8..448bde861b4190a678a8ccb63cade43c4a3d6ad9 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -167,8 +167,10 @@ public class Connection extends SimpleChannelInboundHandler> { - - this.handlingFault = true; - if (this.channel.isOpen()) { -+ net.minecraft.server.level.ServerPlayer player = this.getPlayer(); // Paper - Add API for quit reason - if (throwable instanceof TimeoutException) { - Connection.LOGGER.debug("Timeout", throwable); -+ if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.TIMED_OUT; // Paper - Add API for quit reason - this.disconnect((Component) Component.translatable("disconnect.timeout")); - } else { - MutableComponent ichatmutablecomponent = Component.translatable("disconnect.genericReason", "Internal Exception: " + String.valueOf(throwable)); -@@ -181,6 +183,7 @@ public class Connection extends SimpleChannelInboundHandler> { - disconnectiondetails = new DisconnectionDetails(ichatmutablecomponent); - } - -+ if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.ERRONEOUS_STATE; // Paper - Add API for quit reason - if (flag) { - Connection.LOGGER.debug("Failed to sent packet", throwable); - if (this.getSending() == PacketFlow.CLIENTBOUND) { -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 475ad396d842617b53ccf59fd07bfe1682852e50..6344947f445e1da19d21de67a51b88de65eceb7a 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -321,6 +321,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - public boolean isRealPlayer; // Paper - public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent - public @Nullable String clientBrandName = null; // Paper - Brand support -+ public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event - - public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { - super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); -diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 9a8b08d4b70b8890961e4af7ce6e870aa1c7c810..f8ae8c8eff73e4e87eb34d0f2635517f1688a6f1 100644 ---- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -383,6 +383,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - - private void disconnect0(DisconnectionDetails disconnectiondetails) { - // CraftBukkit end -+ this.player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.KICKED; // Paper - Add API for quit reason - this.connection.send(new ClientboundDisconnectPacket(disconnectiondetails.reason()), PacketSendListener.thenRun(() -> { - this.connection.disconnect(disconnectiondetails); - })); -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index f11bea4618757ac8060098ab7a7a2642ff0a1ae4..e734798640cc016d54c56b7870a1a653353ff709 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -519,7 +519,7 @@ public abstract class PlayerList { - entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper - Inventory close reason - } - -- PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName()))); // Paper - Adventure -+ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName())), entityplayer.quitReason); // Paper - Adventure & Add API for quit reason - this.cserver.getPluginManager().callEvent(playerQuitEvent); - entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); - diff --git a/patches/server/0424-Add-Wandering-Trader-spawn-rate-config-options.patch b/patches/server/0424-Add-Wandering-Trader-spawn-rate-config-options.patch new file mode 100644 index 0000000000..30e4e03f24 --- /dev/null +++ b/patches/server/0424-Add-Wandering-Trader-spawn-rate-config-options.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Thu, 20 Aug 2020 11:20:12 -0700 +Subject: [PATCH] Add Wandering Trader spawn rate config options + +Adds config options for modifying the spawn rates of Wandering Traders. +These values are all easy to understand and configure after a quick read of this +page on the Minecraft wiki: https://minecraft.wiki/wiki/Wandering_Trader#Spawning +Usages of the vanilla WanderingTraderSpawnDelay and WanderingTraderSpawnChance values +in IWorldServerData are removed as they were only used in certain places, with hardcoded +values used in other places. + +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 cfa1787b955fd9b80bf9906b88d423cb59b12ff1..08a3c7140867f339dd99a95094ed0fd8ff344fca 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java ++++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +@@ -40,43 +40,53 @@ public class WanderingTraderSpawner implements CustomSpawner { + + public WanderingTraderSpawner(ServerLevelData properties) { + this.serverLevelData = properties; +- this.tickDelay = 1200; +- this.spawnDelay = properties.getWanderingTraderSpawnDelay(); +- this.spawnChance = properties.getWanderingTraderSpawnChance(); +- if (this.spawnDelay == 0 && this.spawnChance == 0) { +- this.spawnDelay = 24000; +- properties.setWanderingTraderSpawnDelay(this.spawnDelay); +- this.spawnChance = 25; +- properties.setWanderingTraderSpawnChance(this.spawnChance); +- } ++ // Paper start - Add Wandering Trader spawn rate config options ++ this.tickDelay = Integer.MIN_VALUE; ++ //this.spawnDelay = properties.getWanderingTraderSpawnDelay(); // Paper - This value is read from the world file only for the first spawn, after which vanilla uses a hardcoded value ++ //this.spawnChance = properties.getWanderingTraderSpawnChance(); // Paper - This value is read from the world file only for the first spawn, after which vanilla uses a hardcoded value ++ //if (this.spawnDelay == 0 && this.spawnChance == 0) { ++ // this.spawnDelay = 24000; ++ // properties.setWanderingTraderSpawnDelay(this.spawnDelay); ++ // this.spawnChance = 25; ++ // properties.setWanderingTraderSpawnChance(this.spawnChance); ++ //} ++ // Paper end - Add Wandering Trader spawn rate config options + + } + + @Override + public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { ++ // Paper start - Add Wandering Trader spawn rate config options ++ if (this.tickDelay == Integer.MIN_VALUE) { ++ this.tickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; ++ this.spawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; ++ this.spawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; ++ } + if (!world.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) { + return 0; +- } else if (--this.tickDelay > 0) { ++ } else if (this.tickDelay - 1 > 0) { ++ this.tickDelay = this.tickDelay - 1; + return 0; + } else { +- this.tickDelay = 1200; +- this.spawnDelay -= 1200; +- this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); ++ this.tickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; ++ this.spawnDelay = this.spawnDelay - world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; ++ //this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways + if (this.spawnDelay > 0) { + return 0; + } else { +- this.spawnDelay = 24000; ++ this.spawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; + if (!world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { + return 0; + } else { + int i = this.spawnChance; + +- this.spawnChance = Mth.clamp(this.spawnChance + 25, 25, 75); +- this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); ++ // this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways ++ this.spawnChance = Mth.clamp(i + world.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax); + if (this.random.nextInt(100) > i) { + return 0; + } else if (this.spawn(world)) { +- this.spawnChance = 25; ++ this.spawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; ++ // Paper end - Add Wandering Trader spawn rate config options + return 1; + } else { + return 0; diff --git a/patches/server/0425-Add-Destroy-Speed-API.patch b/patches/server/0425-Add-Destroy-Speed-API.patch new file mode 100644 index 0000000000..251968d61c --- /dev/null +++ b/patches/server/0425-Add-Destroy-Speed-API.patch @@ -0,0 +1,220 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ineusia +Date: Mon, 26 Oct 2020 11:48:06 -0500 +Subject: [PATCH] Add Destroy Speed API + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java +index a2fe7149a837040cf9f23eb426d398a5f90be394..27a7852a5d3f8c8960f098646ff5587c50556aa5 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java ++++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java +@@ -153,20 +153,20 @@ public class AttributeInstance { + double d = this.getBaseValue(); + + for (AttributeModifier attributeModifier : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_VALUE)) { +- d += attributeModifier.amount(); ++ d += attributeModifier.amount(); // Paper - destroy speed API - diff on change + } + + double e = d; + + for (AttributeModifier attributeModifier2 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_BASE)) { +- e += d * attributeModifier2.amount(); ++ e += d * attributeModifier2.amount(); // Paper - destroy speed API - diff on change + } + + for (AttributeModifier attributeModifier3 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)) { +- e *= 1.0 + attributeModifier3.amount(); ++ e *= 1.0 + attributeModifier3.amount(); // Paper - destroy speed API - diff on change + } + +- return this.attribute.value().sanitizeValue(e); ++ return attribute.value().sanitizeValue(e); // Paper - destroy speed API - diff on change + } + + private Collection getModifiersOrEmpty(AttributeModifier.Operation operation) { +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 4982950b13cdf1668c0a662b80faf9f700ed584b..78071859e9b745b2497fec7761888b4e65a208a1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +@@ -730,4 +730,35 @@ public class CraftBlockData implements BlockData { + public BlockState createBlockState() { + return CraftBlockStates.getBlockState(this.state, null); + } ++ ++ // Paper start - destroy speed API ++ @Override ++ public float getDestroySpeed(final ItemStack itemStack, final boolean considerEnchants) { ++ net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.unwrap(itemStack); ++ float speed = nmsItemStack.getDestroySpeed(this.state); ++ if (speed > 1.0F && considerEnchants) { ++ final net.minecraft.core.Holder attribute = net.minecraft.world.entity.ai.attributes.Attributes.MINING_EFFICIENCY; ++ // Logic sourced from AttributeInstance#calculateValue ++ final double initialBaseValue = attribute.value().getDefaultValue(); ++ final org.apache.commons.lang3.mutable.MutableDouble modifiedBaseValue = new org.apache.commons.lang3.mutable.MutableDouble(initialBaseValue); ++ final org.apache.commons.lang3.mutable.MutableDouble baseValMul = new org.apache.commons.lang3.mutable.MutableDouble(1); ++ final org.apache.commons.lang3.mutable.MutableDouble totalValMul = new org.apache.commons.lang3.mutable.MutableDouble(1); ++ ++ net.minecraft.world.item.enchantment.EnchantmentHelper.forEachModifier( ++ nmsItemStack, net.minecraft.world.entity.EquipmentSlot.MAINHAND, (attributeHolder, attributeModifier) -> { ++ switch (attributeModifier.operation()) { ++ case ADD_VALUE -> modifiedBaseValue.add(attributeModifier.amount()); ++ case ADD_MULTIPLIED_BASE -> baseValMul.add(attributeModifier.amount()); ++ case ADD_MULTIPLIED_TOTAL -> totalValMul.setValue(totalValMul.doubleValue() * (1D + attributeModifier.amount())); ++ } ++ } ++ ); ++ ++ final double actualModifier = modifiedBaseValue.doubleValue() * baseValMul.doubleValue() * totalValMul.doubleValue(); ++ ++ speed += (float) attribute.value().sanitizeValue(actualModifier); ++ } ++ return speed; ++ } ++ // Paper end - destroy speed API + } +diff --git a/src/test/java/io/papermc/paper/block/CraftBlockDataDestroySpeedTest.java b/src/test/java/io/papermc/paper/block/CraftBlockDataDestroySpeedTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..32d38205a5a72c3c1838ed28cb83bcea5ad59b6b +--- /dev/null ++++ b/src/test/java/io/papermc/paper/block/CraftBlockDataDestroySpeedTest.java +@@ -0,0 +1,138 @@ ++package io.papermc.paper.block; ++ ++import java.util.List; ++import java.util.Optional; ++import net.minecraft.core.Holder; ++import net.minecraft.core.HolderSet; ++import net.minecraft.core.component.DataComponentMap; ++import net.minecraft.core.component.DataComponents; ++import net.minecraft.network.chat.Component; ++import net.minecraft.world.entity.EquipmentSlot; ++import net.minecraft.world.entity.EquipmentSlotGroup; ++import net.minecraft.world.entity.ai.attributes.AttributeInstance; ++import net.minecraft.world.entity.ai.attributes.AttributeModifier; ++import net.minecraft.world.entity.ai.attributes.Attributes; ++import net.minecraft.world.item.Items; ++import net.minecraft.world.item.enchantment.Enchantment; ++import net.minecraft.world.item.enchantment.EnchantmentEffectComponents; ++import net.minecraft.world.item.enchantment.EnchantmentHelper; ++import net.minecraft.world.item.enchantment.ItemEnchantments; ++import net.minecraft.world.item.enchantment.LevelBasedValue; ++import net.minecraft.world.item.enchantment.effects.EnchantmentAttributeEffect; ++import net.minecraft.world.level.block.Blocks; ++import net.minecraft.world.level.block.state.BlockState; ++import org.bukkit.craftbukkit.block.data.CraftBlockData; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.support.environment.AllFeatures; ++import org.bukkit.util.Vector; ++import org.jetbrains.annotations.NotNull; ++import org.junit.jupiter.api.Assertions; ++import org.junit.jupiter.api.Test; ++ ++import static net.minecraft.resources.ResourceLocation.fromNamespaceAndPath; ++ ++/** ++ * CraftBlockData's {@link org.bukkit.craftbukkit.block.data.CraftBlockData#getDestroySpeed(ItemStack, boolean)} ++ * uses a reimplementation of AttributeValue without any map to avoid attribute instance allocation and mutation ++ * for 0 gain. ++ *

++ * This test is responsible for ensuring that said logic emits the expected destroy speed under heavy attribute ++ * modifier use. ++ */ ++@AllFeatures ++public class CraftBlockDataDestroySpeedTest { ++ ++ @Test ++ public void testCorrectEnchantmentDestroySpeedComputation() { ++ // Construct fake enchantment that has *all and multiple of* operations ++ final Enchantment speedEnchantment = speedEnchantment(); ++ final BlockState blockStateToMine = Blocks.STONE.defaultBlockState(); ++ ++ final ItemEnchantments.Mutable mutable = new ItemEnchantments.Mutable(ItemEnchantments.EMPTY); ++ mutable.set(Holder.direct(speedEnchantment), 1); ++ ++ final net.minecraft.world.item.ItemStack itemStack = new net.minecraft.world.item.ItemStack(Items.DIAMOND_PICKAXE); ++ itemStack.set(DataComponents.ENCHANTMENTS, mutable.toImmutable()); ++ ++ // Compute expected value by running the entire attribute instance chain ++ final AttributeInstance dummyInstance = new AttributeInstance(Attributes.MINING_EFFICIENCY, $ -> { ++ }); ++ EnchantmentHelper.forEachModifier(itemStack, EquipmentSlot.MAINHAND, (attributeHolder, attributeModifier) -> { ++ if (attributeHolder.is(Attributes.MINING_EFFICIENCY)) dummyInstance.addTransientModifier(attributeModifier); ++ }); ++ ++ final double toolSpeed = itemStack.getDestroySpeed(blockStateToMine); ++ final double expectedSpeed = toolSpeed <= 1.0F ? toolSpeed : toolSpeed + dummyInstance.getValue(); ++ ++ // API stack + computation ++ final CraftItemStack craftMirror = CraftItemStack.asCraftMirror(itemStack); ++ final CraftBlockData data = CraftBlockData.createData(blockStateToMine); ++ final float actualSpeed = data.getDestroySpeed(craftMirror, true); ++ ++ Assertions.assertEquals(expectedSpeed, actualSpeed, Vector.getEpsilon()); ++ } ++ ++ /** ++ * Complex enchantment that holds attribute modifiers for the mining efficiency. ++ * The enchantment holds 2 of each operation to also ensure that such behaviour works correctly. ++ * ++ * @return the enchantment. ++ */ ++ private static @NotNull Enchantment speedEnchantment() { ++ return new Enchantment( ++ Component.empty(), ++ new Enchantment.EnchantmentDefinition( ++ HolderSet.empty(), ++ Optional.empty(), ++ 0, 0, ++ Enchantment.constantCost(0), ++ Enchantment.constantCost(0), ++ 0, ++ List.of(EquipmentSlotGroup.ANY) ++ ), ++ HolderSet.empty(), ++ DataComponentMap.builder() ++ .set(EnchantmentEffectComponents.ATTRIBUTES, List.of( ++ new EnchantmentAttributeEffect( ++ fromNamespaceAndPath("paper", "base1"), ++ Attributes.MINING_EFFICIENCY, ++ LevelBasedValue.constant(1), ++ AttributeModifier.Operation.ADD_VALUE ++ ), ++ new EnchantmentAttributeEffect( ++ fromNamespaceAndPath("paper", "base2"), ++ Attributes.MINING_EFFICIENCY, ++ LevelBasedValue.perLevel(3), ++ AttributeModifier.Operation.ADD_VALUE ++ ), ++ new EnchantmentAttributeEffect( ++ fromNamespaceAndPath("paper", "base-mul1"), ++ Attributes.MINING_EFFICIENCY, ++ LevelBasedValue.perLevel(7), ++ AttributeModifier.Operation.ADD_MULTIPLIED_BASE ++ ), ++ new EnchantmentAttributeEffect( ++ fromNamespaceAndPath("paper", "base-mul2"), ++ Attributes.MINING_EFFICIENCY, ++ LevelBasedValue.constant(10), ++ AttributeModifier.Operation.ADD_MULTIPLIED_BASE ++ ), ++ new EnchantmentAttributeEffect( ++ fromNamespaceAndPath("paper", "total-mul1"), ++ Attributes.MINING_EFFICIENCY, ++ LevelBasedValue.constant(.2f), ++ AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL ++ ), ++ new EnchantmentAttributeEffect( ++ fromNamespaceAndPath("paper", "total-mul2"), ++ Attributes.MINING_EFFICIENCY, ++ LevelBasedValue.constant(-.5F), ++ AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL ++ ) ++ )) ++ .build() ++ ); ++ } ++ ++} diff --git a/patches/server/0425-Add-Wandering-Trader-spawn-rate-config-options.patch b/patches/server/0425-Add-Wandering-Trader-spawn-rate-config-options.patch deleted file mode 100644 index 30e4e03f24..0000000000 --- a/patches/server/0425-Add-Wandering-Trader-spawn-rate-config-options.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Thu, 20 Aug 2020 11:20:12 -0700 -Subject: [PATCH] Add Wandering Trader spawn rate config options - -Adds config options for modifying the spawn rates of Wandering Traders. -These values are all easy to understand and configure after a quick read of this -page on the Minecraft wiki: https://minecraft.wiki/wiki/Wandering_Trader#Spawning -Usages of the vanilla WanderingTraderSpawnDelay and WanderingTraderSpawnChance values -in IWorldServerData are removed as they were only used in certain places, with hardcoded -values used in other places. - -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 cfa1787b955fd9b80bf9906b88d423cb59b12ff1..08a3c7140867f339dd99a95094ed0fd8ff344fca 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -@@ -40,43 +40,53 @@ public class WanderingTraderSpawner implements CustomSpawner { - - public WanderingTraderSpawner(ServerLevelData properties) { - this.serverLevelData = properties; -- this.tickDelay = 1200; -- this.spawnDelay = properties.getWanderingTraderSpawnDelay(); -- this.spawnChance = properties.getWanderingTraderSpawnChance(); -- if (this.spawnDelay == 0 && this.spawnChance == 0) { -- this.spawnDelay = 24000; -- properties.setWanderingTraderSpawnDelay(this.spawnDelay); -- this.spawnChance = 25; -- properties.setWanderingTraderSpawnChance(this.spawnChance); -- } -+ // Paper start - Add Wandering Trader spawn rate config options -+ this.tickDelay = Integer.MIN_VALUE; -+ //this.spawnDelay = properties.getWanderingTraderSpawnDelay(); // Paper - This value is read from the world file only for the first spawn, after which vanilla uses a hardcoded value -+ //this.spawnChance = properties.getWanderingTraderSpawnChance(); // Paper - This value is read from the world file only for the first spawn, after which vanilla uses a hardcoded value -+ //if (this.spawnDelay == 0 && this.spawnChance == 0) { -+ // this.spawnDelay = 24000; -+ // properties.setWanderingTraderSpawnDelay(this.spawnDelay); -+ // this.spawnChance = 25; -+ // properties.setWanderingTraderSpawnChance(this.spawnChance); -+ //} -+ // Paper end - Add Wandering Trader spawn rate config options - - } - - @Override - public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { -+ // Paper start - Add Wandering Trader spawn rate config options -+ if (this.tickDelay == Integer.MIN_VALUE) { -+ this.tickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; -+ this.spawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; -+ this.spawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; -+ } - if (!world.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) { - return 0; -- } else if (--this.tickDelay > 0) { -+ } else if (this.tickDelay - 1 > 0) { -+ this.tickDelay = this.tickDelay - 1; - return 0; - } else { -- this.tickDelay = 1200; -- this.spawnDelay -= 1200; -- this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); -+ this.tickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; -+ this.spawnDelay = this.spawnDelay - world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; -+ //this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways - if (this.spawnDelay > 0) { - return 0; - } else { -- this.spawnDelay = 24000; -+ this.spawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; - if (!world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { - return 0; - } else { - int i = this.spawnChance; - -- this.spawnChance = Mth.clamp(this.spawnChance + 25, 25, 75); -- this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); -+ // this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways -+ this.spawnChance = Mth.clamp(i + world.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax); - if (this.random.nextInt(100) > i) { - return 0; - } else if (this.spawn(world)) { -- this.spawnChance = 25; -+ this.spawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; -+ // Paper end - Add Wandering Trader spawn rate config options - return 1; - } else { - return 0; diff --git a/patches/server/0426-Add-Destroy-Speed-API.patch b/patches/server/0426-Add-Destroy-Speed-API.patch deleted file mode 100644 index 251968d61c..0000000000 --- a/patches/server/0426-Add-Destroy-Speed-API.patch +++ /dev/null @@ -1,220 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ineusia -Date: Mon, 26 Oct 2020 11:48:06 -0500 -Subject: [PATCH] Add Destroy Speed API - -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java -index a2fe7149a837040cf9f23eb426d398a5f90be394..27a7852a5d3f8c8960f098646ff5587c50556aa5 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java -+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java -@@ -153,20 +153,20 @@ public class AttributeInstance { - double d = this.getBaseValue(); - - for (AttributeModifier attributeModifier : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_VALUE)) { -- d += attributeModifier.amount(); -+ d += attributeModifier.amount(); // Paper - destroy speed API - diff on change - } - - double e = d; - - for (AttributeModifier attributeModifier2 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_BASE)) { -- e += d * attributeModifier2.amount(); -+ e += d * attributeModifier2.amount(); // Paper - destroy speed API - diff on change - } - - for (AttributeModifier attributeModifier3 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)) { -- e *= 1.0 + attributeModifier3.amount(); -+ e *= 1.0 + attributeModifier3.amount(); // Paper - destroy speed API - diff on change - } - -- return this.attribute.value().sanitizeValue(e); -+ return attribute.value().sanitizeValue(e); // Paper - destroy speed API - diff on change - } - - private Collection getModifiersOrEmpty(AttributeModifier.Operation operation) { -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 4982950b13cdf1668c0a662b80faf9f700ed584b..78071859e9b745b2497fec7761888b4e65a208a1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -@@ -730,4 +730,35 @@ public class CraftBlockData implements BlockData { - public BlockState createBlockState() { - return CraftBlockStates.getBlockState(this.state, null); - } -+ -+ // Paper start - destroy speed API -+ @Override -+ public float getDestroySpeed(final ItemStack itemStack, final boolean considerEnchants) { -+ net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.unwrap(itemStack); -+ float speed = nmsItemStack.getDestroySpeed(this.state); -+ if (speed > 1.0F && considerEnchants) { -+ final net.minecraft.core.Holder attribute = net.minecraft.world.entity.ai.attributes.Attributes.MINING_EFFICIENCY; -+ // Logic sourced from AttributeInstance#calculateValue -+ final double initialBaseValue = attribute.value().getDefaultValue(); -+ final org.apache.commons.lang3.mutable.MutableDouble modifiedBaseValue = new org.apache.commons.lang3.mutable.MutableDouble(initialBaseValue); -+ final org.apache.commons.lang3.mutable.MutableDouble baseValMul = new org.apache.commons.lang3.mutable.MutableDouble(1); -+ final org.apache.commons.lang3.mutable.MutableDouble totalValMul = new org.apache.commons.lang3.mutable.MutableDouble(1); -+ -+ net.minecraft.world.item.enchantment.EnchantmentHelper.forEachModifier( -+ nmsItemStack, net.minecraft.world.entity.EquipmentSlot.MAINHAND, (attributeHolder, attributeModifier) -> { -+ switch (attributeModifier.operation()) { -+ case ADD_VALUE -> modifiedBaseValue.add(attributeModifier.amount()); -+ case ADD_MULTIPLIED_BASE -> baseValMul.add(attributeModifier.amount()); -+ case ADD_MULTIPLIED_TOTAL -> totalValMul.setValue(totalValMul.doubleValue() * (1D + attributeModifier.amount())); -+ } -+ } -+ ); -+ -+ final double actualModifier = modifiedBaseValue.doubleValue() * baseValMul.doubleValue() * totalValMul.doubleValue(); -+ -+ speed += (float) attribute.value().sanitizeValue(actualModifier); -+ } -+ return speed; -+ } -+ // Paper end - destroy speed API - } -diff --git a/src/test/java/io/papermc/paper/block/CraftBlockDataDestroySpeedTest.java b/src/test/java/io/papermc/paper/block/CraftBlockDataDestroySpeedTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..32d38205a5a72c3c1838ed28cb83bcea5ad59b6b ---- /dev/null -+++ b/src/test/java/io/papermc/paper/block/CraftBlockDataDestroySpeedTest.java -@@ -0,0 +1,138 @@ -+package io.papermc.paper.block; -+ -+import java.util.List; -+import java.util.Optional; -+import net.minecraft.core.Holder; -+import net.minecraft.core.HolderSet; -+import net.minecraft.core.component.DataComponentMap; -+import net.minecraft.core.component.DataComponents; -+import net.minecraft.network.chat.Component; -+import net.minecraft.world.entity.EquipmentSlot; -+import net.minecraft.world.entity.EquipmentSlotGroup; -+import net.minecraft.world.entity.ai.attributes.AttributeInstance; -+import net.minecraft.world.entity.ai.attributes.AttributeModifier; -+import net.minecraft.world.entity.ai.attributes.Attributes; -+import net.minecraft.world.item.Items; -+import net.minecraft.world.item.enchantment.Enchantment; -+import net.minecraft.world.item.enchantment.EnchantmentEffectComponents; -+import net.minecraft.world.item.enchantment.EnchantmentHelper; -+import net.minecraft.world.item.enchantment.ItemEnchantments; -+import net.minecraft.world.item.enchantment.LevelBasedValue; -+import net.minecraft.world.item.enchantment.effects.EnchantmentAttributeEffect; -+import net.minecraft.world.level.block.Blocks; -+import net.minecraft.world.level.block.state.BlockState; -+import org.bukkit.craftbukkit.block.data.CraftBlockData; -+import org.bukkit.craftbukkit.inventory.CraftItemStack; -+import org.bukkit.inventory.ItemStack; -+import org.bukkit.support.environment.AllFeatures; -+import org.bukkit.util.Vector; -+import org.jetbrains.annotations.NotNull; -+import org.junit.jupiter.api.Assertions; -+import org.junit.jupiter.api.Test; -+ -+import static net.minecraft.resources.ResourceLocation.fromNamespaceAndPath; -+ -+/** -+ * CraftBlockData's {@link org.bukkit.craftbukkit.block.data.CraftBlockData#getDestroySpeed(ItemStack, boolean)} -+ * uses a reimplementation of AttributeValue without any map to avoid attribute instance allocation and mutation -+ * for 0 gain. -+ *

-+ * This test is responsible for ensuring that said logic emits the expected destroy speed under heavy attribute -+ * modifier use. -+ */ -+@AllFeatures -+public class CraftBlockDataDestroySpeedTest { -+ -+ @Test -+ public void testCorrectEnchantmentDestroySpeedComputation() { -+ // Construct fake enchantment that has *all and multiple of* operations -+ final Enchantment speedEnchantment = speedEnchantment(); -+ final BlockState blockStateToMine = Blocks.STONE.defaultBlockState(); -+ -+ final ItemEnchantments.Mutable mutable = new ItemEnchantments.Mutable(ItemEnchantments.EMPTY); -+ mutable.set(Holder.direct(speedEnchantment), 1); -+ -+ final net.minecraft.world.item.ItemStack itemStack = new net.minecraft.world.item.ItemStack(Items.DIAMOND_PICKAXE); -+ itemStack.set(DataComponents.ENCHANTMENTS, mutable.toImmutable()); -+ -+ // Compute expected value by running the entire attribute instance chain -+ final AttributeInstance dummyInstance = new AttributeInstance(Attributes.MINING_EFFICIENCY, $ -> { -+ }); -+ EnchantmentHelper.forEachModifier(itemStack, EquipmentSlot.MAINHAND, (attributeHolder, attributeModifier) -> { -+ if (attributeHolder.is(Attributes.MINING_EFFICIENCY)) dummyInstance.addTransientModifier(attributeModifier); -+ }); -+ -+ final double toolSpeed = itemStack.getDestroySpeed(blockStateToMine); -+ final double expectedSpeed = toolSpeed <= 1.0F ? toolSpeed : toolSpeed + dummyInstance.getValue(); -+ -+ // API stack + computation -+ final CraftItemStack craftMirror = CraftItemStack.asCraftMirror(itemStack); -+ final CraftBlockData data = CraftBlockData.createData(blockStateToMine); -+ final float actualSpeed = data.getDestroySpeed(craftMirror, true); -+ -+ Assertions.assertEquals(expectedSpeed, actualSpeed, Vector.getEpsilon()); -+ } -+ -+ /** -+ * Complex enchantment that holds attribute modifiers for the mining efficiency. -+ * The enchantment holds 2 of each operation to also ensure that such behaviour works correctly. -+ * -+ * @return the enchantment. -+ */ -+ private static @NotNull Enchantment speedEnchantment() { -+ return new Enchantment( -+ Component.empty(), -+ new Enchantment.EnchantmentDefinition( -+ HolderSet.empty(), -+ Optional.empty(), -+ 0, 0, -+ Enchantment.constantCost(0), -+ Enchantment.constantCost(0), -+ 0, -+ List.of(EquipmentSlotGroup.ANY) -+ ), -+ HolderSet.empty(), -+ DataComponentMap.builder() -+ .set(EnchantmentEffectComponents.ATTRIBUTES, List.of( -+ new EnchantmentAttributeEffect( -+ fromNamespaceAndPath("paper", "base1"), -+ Attributes.MINING_EFFICIENCY, -+ LevelBasedValue.constant(1), -+ AttributeModifier.Operation.ADD_VALUE -+ ), -+ new EnchantmentAttributeEffect( -+ fromNamespaceAndPath("paper", "base2"), -+ Attributes.MINING_EFFICIENCY, -+ LevelBasedValue.perLevel(3), -+ AttributeModifier.Operation.ADD_VALUE -+ ), -+ new EnchantmentAttributeEffect( -+ fromNamespaceAndPath("paper", "base-mul1"), -+ Attributes.MINING_EFFICIENCY, -+ LevelBasedValue.perLevel(7), -+ AttributeModifier.Operation.ADD_MULTIPLIED_BASE -+ ), -+ new EnchantmentAttributeEffect( -+ fromNamespaceAndPath("paper", "base-mul2"), -+ Attributes.MINING_EFFICIENCY, -+ LevelBasedValue.constant(10), -+ AttributeModifier.Operation.ADD_MULTIPLIED_BASE -+ ), -+ new EnchantmentAttributeEffect( -+ fromNamespaceAndPath("paper", "total-mul1"), -+ Attributes.MINING_EFFICIENCY, -+ LevelBasedValue.constant(.2f), -+ AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL -+ ), -+ new EnchantmentAttributeEffect( -+ fromNamespaceAndPath("paper", "total-mul2"), -+ Attributes.MINING_EFFICIENCY, -+ LevelBasedValue.constant(-.5F), -+ AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL -+ ) -+ )) -+ .build() -+ ); -+ } -+ -+} diff --git a/patches/server/0426-Fix-Player-spawnParticle-x-y-z-precision-loss.patch b/patches/server/0426-Fix-Player-spawnParticle-x-y-z-precision-loss.patch new file mode 100644 index 0000000000..92b41a4864 --- /dev/null +++ b/patches/server/0426-Fix-Player-spawnParticle-x-y-z-precision-loss.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Esophose +Date: Sat, 3 Oct 2020 18:57:47 -0600 +Subject: [PATCH] Fix Player spawnParticle x/y/z precision loss + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 42ee772b76b7601ad59378c81277fe0c60e4438b..0aaea6091c5828782ed606d250423f3d75b9b27f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -2709,7 +2709,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + @Override + public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) { +- ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(CraftParticle.createParticleParam(particle, data), false, force, (float) x, (float) y, (float) z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count); ++ ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(CraftParticle.createParticleParam(particle, data), false, force, x, y, z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count); // Paper - fix x/y/z precision loss + this.getHandle().connection.send(packetplayoutworldparticles); + } + diff --git a/patches/server/0427-Add-LivingEntity-clearActiveItem.patch b/patches/server/0427-Add-LivingEntity-clearActiveItem.patch new file mode 100644 index 0000000000..f470d50f88 --- /dev/null +++ b/patches/server/0427-Add-LivingEntity-clearActiveItem.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Anrza +Date: Wed, 15 Jul 2020 12:08:49 +0200 +Subject: [PATCH] Add LivingEntity#clearActiveItem + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index e979681142bd08aeb00a98b79789a8f41b2a37af..c19694876007f711dfdcf58ef435a839b1e31d72 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -967,6 +967,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + return this.getHandle().getUseItem().asBukkitMirror(); + } + ++ // Paper start ++ @Override ++ public void clearActiveItem() { ++ getHandle().stopUsingItem(); ++ } ++ // Paper end ++ + @Override + public int getActiveItemRemainingTime() { + return this.getHandle().getUseItemRemainingTicks(); diff --git a/patches/server/0427-Fix-Player-spawnParticle-x-y-z-precision-loss.patch b/patches/server/0427-Fix-Player-spawnParticle-x-y-z-precision-loss.patch deleted file mode 100644 index 92b41a4864..0000000000 --- a/patches/server/0427-Fix-Player-spawnParticle-x-y-z-precision-loss.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Esophose -Date: Sat, 3 Oct 2020 18:57:47 -0600 -Subject: [PATCH] Fix Player spawnParticle x/y/z precision loss - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 42ee772b76b7601ad59378c81277fe0c60e4438b..0aaea6091c5828782ed606d250423f3d75b9b27f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2709,7 +2709,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) { -- ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(CraftParticle.createParticleParam(particle, data), false, force, (float) x, (float) y, (float) z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count); -+ ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(CraftParticle.createParticleParam(particle, data), false, force, x, y, z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count); // Paper - fix x/y/z precision loss - this.getHandle().connection.send(packetplayoutworldparticles); - } - diff --git a/patches/server/0428-Add-LivingEntity-clearActiveItem.patch b/patches/server/0428-Add-LivingEntity-clearActiveItem.patch deleted file mode 100644 index f470d50f88..0000000000 --- a/patches/server/0428-Add-LivingEntity-clearActiveItem.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Anrza -Date: Wed, 15 Jul 2020 12:08:49 +0200 -Subject: [PATCH] Add LivingEntity#clearActiveItem - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index e979681142bd08aeb00a98b79789a8f41b2a37af..c19694876007f711dfdcf58ef435a839b1e31d72 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -967,6 +967,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - return this.getHandle().getUseItem().asBukkitMirror(); - } - -+ // Paper start -+ @Override -+ public void clearActiveItem() { -+ getHandle().stopUsingItem(); -+ } -+ // Paper end -+ - @Override - public int getActiveItemRemainingTime() { - return this.getHandle().getUseItemRemainingTicks(); diff --git a/patches/server/0428-Add-PlayerItemCooldownEvent.patch b/patches/server/0428-Add-PlayerItemCooldownEvent.patch new file mode 100644 index 0000000000..773d0201e7 --- /dev/null +++ b/patches/server/0428-Add-PlayerItemCooldownEvent.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Tue, 25 Aug 2020 13:48:33 +0200 +Subject: [PATCH] Add PlayerItemCooldownEvent + + +diff --git a/src/main/java/net/minecraft/world/item/ItemCooldowns.java b/src/main/java/net/minecraft/world/item/ItemCooldowns.java +index 2add88d2543b2e1143bd4b1c53946d7ba3f399da..c7a21b33db802fa6b64865ff2b4f0941279b72cb 100644 +--- a/src/main/java/net/minecraft/world/item/ItemCooldowns.java ++++ b/src/main/java/net/minecraft/world/item/ItemCooldowns.java +@@ -56,6 +56,13 @@ public class ItemCooldowns { + } + + public void addCooldown(ResourceLocation groupId, int duration) { ++ // Paper start - Item cooldown events ++ this.addCooldown(groupId, duration, true); ++ } ++ ++ public void addCooldown(ResourceLocation groupId, int duration, boolean callEvent) { ++ // Event called in server override ++ // Paper end - Item cooldown events + this.cooldowns.put(groupId, new ItemCooldowns.CooldownInstance(this.tickCount, this.tickCount + duration)); + this.onCooldownStarted(groupId, duration); + } +diff --git a/src/main/java/net/minecraft/world/item/ServerItemCooldowns.java b/src/main/java/net/minecraft/world/item/ServerItemCooldowns.java +index 3a45a149ec4a28f25ea9e45803ecbb7392b63f86..7b634a0a8639524a276cd6c5d6535e28a580b20a 100644 +--- a/src/main/java/net/minecraft/world/item/ServerItemCooldowns.java ++++ b/src/main/java/net/minecraft/world/item/ServerItemCooldowns.java +@@ -11,6 +11,39 @@ public class ServerItemCooldowns extends ItemCooldowns { + this.player = player; + } + ++ // Paper start - Add PlayerItemCooldownEvent ++ @Override ++ public void addCooldown(ItemStack item, int duration) { ++ final ResourceLocation cooldownGroup = this.getCooldownGroup(item); ++ final io.papermc.paper.event.player.PlayerItemCooldownEvent event = new io.papermc.paper.event.player.PlayerItemCooldownEvent( ++ this.player.getBukkitEntity(), ++ org.bukkit.craftbukkit.inventory.CraftItemType.minecraftToBukkit(item.getItem()), ++ org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(cooldownGroup), ++ duration ++ ); ++ if (event.callEvent()) { ++ super.addCooldown(cooldownGroup, event.getCooldown(), false); ++ } ++ } ++ ++ @Override ++ public void addCooldown(ResourceLocation groupId, int duration, boolean callEvent) { ++ if (callEvent) { ++ final io.papermc.paper.event.player.PlayerItemGroupCooldownEvent event = new io.papermc.paper.event.player.PlayerItemGroupCooldownEvent( ++ this.player.getBukkitEntity(), ++ org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(groupId), ++ duration ++ ); ++ if (!event.callEvent()) { ++ return; ++ } ++ ++ duration = event.getCooldown(); ++ } ++ super.addCooldown(groupId, duration, false); ++ } ++ // Paper end - Add PlayerItemCooldownEvent ++ + @Override + protected void onCooldownStarted(ResourceLocation groupId, int duration) { + super.onCooldownStarted(groupId, duration); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +index 9022555db0df8c269fc039c895422cf36c08097e..8012ee71e1ce9f174eb5c4ac9eb8372b81e0a78c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -619,7 +619,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + } + + ItemCooldowns.CooldownInstance cooldown = this.getHandle().getCooldowns().cooldowns.get(group); +- return (cooldown == null) ? 0 : Math.max(0, cooldown.endTime - this.getHandle().getCooldowns().tickCount); ++ return (cooldown == null) ? 0 : Math.max(0, cooldown.endTime() - this.getHandle().getCooldowns().tickCount); + } + + @Override diff --git a/patches/server/0429-Add-PlayerItemCooldownEvent.patch b/patches/server/0429-Add-PlayerItemCooldownEvent.patch deleted file mode 100644 index 773d0201e7..0000000000 --- a/patches/server/0429-Add-PlayerItemCooldownEvent.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Tue, 25 Aug 2020 13:48:33 +0200 -Subject: [PATCH] Add PlayerItemCooldownEvent - - -diff --git a/src/main/java/net/minecraft/world/item/ItemCooldowns.java b/src/main/java/net/minecraft/world/item/ItemCooldowns.java -index 2add88d2543b2e1143bd4b1c53946d7ba3f399da..c7a21b33db802fa6b64865ff2b4f0941279b72cb 100644 ---- a/src/main/java/net/minecraft/world/item/ItemCooldowns.java -+++ b/src/main/java/net/minecraft/world/item/ItemCooldowns.java -@@ -56,6 +56,13 @@ public class ItemCooldowns { - } - - public void addCooldown(ResourceLocation groupId, int duration) { -+ // Paper start - Item cooldown events -+ this.addCooldown(groupId, duration, true); -+ } -+ -+ public void addCooldown(ResourceLocation groupId, int duration, boolean callEvent) { -+ // Event called in server override -+ // Paper end - Item cooldown events - this.cooldowns.put(groupId, new ItemCooldowns.CooldownInstance(this.tickCount, this.tickCount + duration)); - this.onCooldownStarted(groupId, duration); - } -diff --git a/src/main/java/net/minecraft/world/item/ServerItemCooldowns.java b/src/main/java/net/minecraft/world/item/ServerItemCooldowns.java -index 3a45a149ec4a28f25ea9e45803ecbb7392b63f86..7b634a0a8639524a276cd6c5d6535e28a580b20a 100644 ---- a/src/main/java/net/minecraft/world/item/ServerItemCooldowns.java -+++ b/src/main/java/net/minecraft/world/item/ServerItemCooldowns.java -@@ -11,6 +11,39 @@ public class ServerItemCooldowns extends ItemCooldowns { - this.player = player; - } - -+ // Paper start - Add PlayerItemCooldownEvent -+ @Override -+ public void addCooldown(ItemStack item, int duration) { -+ final ResourceLocation cooldownGroup = this.getCooldownGroup(item); -+ final io.papermc.paper.event.player.PlayerItemCooldownEvent event = new io.papermc.paper.event.player.PlayerItemCooldownEvent( -+ this.player.getBukkitEntity(), -+ org.bukkit.craftbukkit.inventory.CraftItemType.minecraftToBukkit(item.getItem()), -+ org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(cooldownGroup), -+ duration -+ ); -+ if (event.callEvent()) { -+ super.addCooldown(cooldownGroup, event.getCooldown(), false); -+ } -+ } -+ -+ @Override -+ public void addCooldown(ResourceLocation groupId, int duration, boolean callEvent) { -+ if (callEvent) { -+ final io.papermc.paper.event.player.PlayerItemGroupCooldownEvent event = new io.papermc.paper.event.player.PlayerItemGroupCooldownEvent( -+ this.player.getBukkitEntity(), -+ org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(groupId), -+ duration -+ ); -+ if (!event.callEvent()) { -+ return; -+ } -+ -+ duration = event.getCooldown(); -+ } -+ super.addCooldown(groupId, duration, false); -+ } -+ // Paper end - Add PlayerItemCooldownEvent -+ - @Override - protected void onCooldownStarted(ResourceLocation groupId, int duration) { - super.onCooldownStarted(groupId, duration); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 9022555db0df8c269fc039c895422cf36c08097e..8012ee71e1ce9f174eb5c4ac9eb8372b81e0a78c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -619,7 +619,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - } - - ItemCooldowns.CooldownInstance cooldown = this.getHandle().getCooldowns().cooldowns.get(group); -- return (cooldown == null) ? 0 : Math.max(0, cooldown.endTime - this.getHandle().getCooldowns().tickCount); -+ return (cooldown == null) ? 0 : Math.max(0, cooldown.endTime() - this.getHandle().getCooldowns().tickCount); - } - - @Override diff --git a/patches/server/0429-Significantly-improve-performance-of-the-end-generat.patch b/patches/server/0429-Significantly-improve-performance-of-the-end-generat.patch new file mode 100644 index 0000000000..ed3ee50bc9 --- /dev/null +++ b/patches/server/0429-Significantly-improve-performance-of-the-end-generat.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SuperCoder7979 <25208576+SuperCoder7979@users.noreply.github.com> +Date: Tue, 3 Nov 2020 23:48:05 -0600 +Subject: [PATCH] Significantly improve performance of the end generation + +This patch implements a noise cache for the end which significantly reduces the computation time of generation. This results in about a 3x improvement. + +Original code by SuperCoder7979 and Gegy in Lithium, licensed under LGPL-3.0 (Source: https://github.com/jellysquid3/lithium-fabric) + +Co-authored-by: Gegy +Co-authored-by: Dylan Xaldin +Co-authored-by: pop4959 + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java +index b09bc1dac649ce9f4826edc1923c843804226993..ac8447e20531ad59d5e26c6db541d6e844d56c0f 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java +@@ -509,6 +509,16 @@ public final class DensityFunctions { + ); + private static final float ISLAND_THRESHOLD = -0.9F; + private final SimplexNoise islandNoise; ++ // Paper start - Perf: Optimize end generation ++ private static final class NoiseCache { ++ public long[] keys = new long[8192]; ++ public float[] values = new float[8192]; ++ public NoiseCache() { ++ java.util.Arrays.fill(keys, Long.MIN_VALUE); ++ } ++ } ++ private static final ThreadLocal> noiseCache = ThreadLocal.withInitial(java.util.WeakHashMap::new); ++ // Paper end - Perf: Optimize end generation + + public EndIslandDensityFunction(long seed) { + RandomSource randomSource = new LegacyRandomSource(seed); +@@ -524,12 +534,26 @@ public final class DensityFunctions { + float f = 100.0F - Mth.sqrt((long) x * (long) x + (long) z * (long) z) * 8.0F; // Paper - cast ints to long to avoid integer overflow + f = Mth.clamp(f, -100.0F, 80.0F); + ++ NoiseCache cache = noiseCache.get().computeIfAbsent(sampler, noiseKey -> new NoiseCache()); // Paper - Perf: Optimize end generation + for (int m = -12; m <= 12; m++) { + for (int n = -12; n <= 12; n++) { + long o = (long)(i + m); + long p = (long)(j + n); +- if (o * o + p * p > 4096L && sampler.getValue((double)o, (double)p) < -0.9F) { +- float g = (Mth.abs((float)o) * 3439.0F + Mth.abs((float)p) * 147.0F) % 13.0F + 9.0F; ++ // Paper start - Perf: Optimize end generation by using a noise cache ++ long key = net.minecraft.world.level.ChunkPos.asLong((int) o, (int) p); ++ int index = (int) it.unimi.dsi.fastutil.HashCommon.mix(key) & 8191; ++ float g = Float.MIN_VALUE; ++ if (cache.keys[index] == key) { ++ g = cache.values[index]; ++ } else { ++ if (o * o + p * p > 4096L && sampler.getValue((double)o, (double)p) < -0.9F) { ++ g = (Mth.abs((float)o) * 3439.0F + Mth.abs((float)p) * 147.0F) % 13.0F + 9.0F; ++ } ++ cache.keys[index] = key; ++ cache.values[index] = g; ++ } ++ if (g != Float.MIN_VALUE) { ++ // Paper end - Perf: Optimize end generation + float h = (float)(k - m * 2); + float q = (float)(l - n * 2); + float r = 100.0F - Mth.sqrt(h * h + q * q) * g; diff --git a/patches/server/0430-More-lightning-API.patch b/patches/server/0430-More-lightning-API.patch new file mode 100644 index 0000000000..967871902a --- /dev/null +++ b/patches/server/0430-More-lightning-API.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Sun, 26 Jul 2020 14:44:09 +0200 +Subject: [PATCH] More lightning API + +== AT == +public net.minecraft.world.entity.LightningBolt life +public net.minecraft.world.entity.LightningBolt flashes + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java +index 0b2ba5c93355a5b7548d4634d964732e45477a34..6fed8075aa75e3852dc826a45ca44603c0446a56 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java +@@ -66,4 +66,23 @@ public class CraftLightningStrike extends CraftEntity implements LightningStrike + return this.spigot; + } + // Spigot end ++ ++ // Paper start ++ @Override ++ public int getFlashCount() { ++ return getHandle().flashes; ++ } ++ ++ @Override ++ public void setFlashCount(int flashes) { ++ com.google.common.base.Preconditions.checkArgument(flashes >= 0, "Flashes has to be a positive number!"); ++ getHandle().flashes = flashes; ++ } ++ ++ @Override ++ public @org.jetbrains.annotations.Nullable org.bukkit.entity.Entity getCausingEntity() { ++ final var cause = this.getHandle().getCause(); ++ return cause == null ? null : cause.getBukkitEntity(); ++ } ++ // Paper end + } diff --git a/patches/server/0430-Significantly-improve-performance-of-the-end-generat.patch b/patches/server/0430-Significantly-improve-performance-of-the-end-generat.patch deleted file mode 100644 index ed3ee50bc9..0000000000 --- a/patches/server/0430-Significantly-improve-performance-of-the-end-generat.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SuperCoder7979 <25208576+SuperCoder7979@users.noreply.github.com> -Date: Tue, 3 Nov 2020 23:48:05 -0600 -Subject: [PATCH] Significantly improve performance of the end generation - -This patch implements a noise cache for the end which significantly reduces the computation time of generation. This results in about a 3x improvement. - -Original code by SuperCoder7979 and Gegy in Lithium, licensed under LGPL-3.0 (Source: https://github.com/jellysquid3/lithium-fabric) - -Co-authored-by: Gegy -Co-authored-by: Dylan Xaldin -Co-authored-by: pop4959 - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java -index b09bc1dac649ce9f4826edc1923c843804226993..ac8447e20531ad59d5e26c6db541d6e844d56c0f 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java -@@ -509,6 +509,16 @@ public final class DensityFunctions { - ); - private static final float ISLAND_THRESHOLD = -0.9F; - private final SimplexNoise islandNoise; -+ // Paper start - Perf: Optimize end generation -+ private static final class NoiseCache { -+ public long[] keys = new long[8192]; -+ public float[] values = new float[8192]; -+ public NoiseCache() { -+ java.util.Arrays.fill(keys, Long.MIN_VALUE); -+ } -+ } -+ private static final ThreadLocal> noiseCache = ThreadLocal.withInitial(java.util.WeakHashMap::new); -+ // Paper end - Perf: Optimize end generation - - public EndIslandDensityFunction(long seed) { - RandomSource randomSource = new LegacyRandomSource(seed); -@@ -524,12 +534,26 @@ public final class DensityFunctions { - float f = 100.0F - Mth.sqrt((long) x * (long) x + (long) z * (long) z) * 8.0F; // Paper - cast ints to long to avoid integer overflow - f = Mth.clamp(f, -100.0F, 80.0F); - -+ NoiseCache cache = noiseCache.get().computeIfAbsent(sampler, noiseKey -> new NoiseCache()); // Paper - Perf: Optimize end generation - for (int m = -12; m <= 12; m++) { - for (int n = -12; n <= 12; n++) { - long o = (long)(i + m); - long p = (long)(j + n); -- if (o * o + p * p > 4096L && sampler.getValue((double)o, (double)p) < -0.9F) { -- float g = (Mth.abs((float)o) * 3439.0F + Mth.abs((float)p) * 147.0F) % 13.0F + 9.0F; -+ // Paper start - Perf: Optimize end generation by using a noise cache -+ long key = net.minecraft.world.level.ChunkPos.asLong((int) o, (int) p); -+ int index = (int) it.unimi.dsi.fastutil.HashCommon.mix(key) & 8191; -+ float g = Float.MIN_VALUE; -+ if (cache.keys[index] == key) { -+ g = cache.values[index]; -+ } else { -+ if (o * o + p * p > 4096L && sampler.getValue((double)o, (double)p) < -0.9F) { -+ g = (Mth.abs((float)o) * 3439.0F + Mth.abs((float)p) * 147.0F) % 13.0F + 9.0F; -+ } -+ cache.keys[index] = key; -+ cache.values[index] = g; -+ } -+ if (g != Float.MIN_VALUE) { -+ // Paper end - Perf: Optimize end generation - float h = (float)(k - m * 2); - float q = (float)(l - n * 2); - float r = 100.0F - Mth.sqrt(h * h + q * q) * g; diff --git a/patches/server/0431-Climbing-should-not-bypass-cramming-gamerule.patch b/patches/server/0431-Climbing-should-not-bypass-cramming-gamerule.patch new file mode 100644 index 0000000000..b6573a018f --- /dev/null +++ b/patches/server/0431-Climbing-should-not-bypass-cramming-gamerule.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 23 Aug 2020 20:59:00 +0200 +Subject: [PATCH] Climbing should not bypass cramming gamerule + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 1efaae5d9dab0bbcc2bbef772eb0f5cdf8ff384c..20e6b199758130d5c758c79488031c40849cc51d 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2219,6 +2219,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public boolean isPushable() { ++ // Paper start - Climbing should not bypass cramming gamerule ++ return isCollidable(false); ++ } ++ ++ public boolean isCollidable(boolean ignoreClimbing) { ++ // Paper end - Climbing should not bypass cramming gamerule + return false; + } + +diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java +index b8d57e25851dd7da905100dfd4022e4b99fd7f02..721321a19ce056f82de2bef44a8791dc9d5b3418 100644 +--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java ++++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java +@@ -45,11 +45,16 @@ public final class EntitySelector { + } + + public static Predicate pushableBy(Entity entity) { ++ // Paper start - Climbing should not bypass cramming gamerule ++ return pushable(entity, false); ++ } ++ public static Predicate pushable(Entity entity, boolean ignoreClimbing) { ++ // Paper end - Climbing should not bypass cramming gamerule + PlayerTeam scoreboardteam = entity.getTeam(); + Team.CollisionRule scoreboardteambase_enumteampush = scoreboardteam == null ? Team.CollisionRule.ALWAYS : scoreboardteam.getCollisionRule(); + + return (Predicate) (scoreboardteambase_enumteampush == Team.CollisionRule.NEVER ? Predicates.alwaysFalse() : EntitySelector.NO_SPECTATORS.and((entity1) -> { +- if (!entity1.canCollideWithBukkit(entity) || !entity.canCollideWithBukkit(entity1)) { // CraftBukkit - collidable API ++ if (!entity1.isCollidable(ignoreClimbing) || !entity1.canCollideWithBukkit(entity) || !entity.canCollideWithBukkit(entity1)) { // CraftBukkit - collidable API // Paper - Climbing should not bypass cramming gamerule + return false; + } else if (entity1 instanceof Player && entity instanceof Player && !io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions) { // Paper - Configurable player collision + return false; +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index b742a42b2c86db79fb88399f40e8682afd600507..f025d36c8ae8606172e8166721f09c851784c3cc 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3722,7 +3722,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + return; + } + // Paper end - don't run getEntities if we're not going to use its result +- List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); ++ List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushable(this, this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule)); // Paper - Climbing should not bypass cramming gamerule + + if (!list.isEmpty()) { + // Paper - don't run getEntities if we're not going to use its result; moved up +@@ -3923,9 +3923,16 @@ public abstract class LivingEntity extends Entity implements Attackable { + return !this.isRemoved() && this.collides; // CraftBukkit + } + ++ // Paper start - Climbing should not bypass cramming gamerule + @Override + public boolean isPushable() { +- return this.isAlive() && !this.isSpectator() && !this.onClimbable() && this.collides; // CraftBukkit ++ return this.isCollidable(this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule); ++ } ++ ++ @Override ++ public boolean isCollidable(boolean ignoreClimbing) { ++ return this.isAlive() && !this.isSpectator() && (ignoreClimbing || !this.onClimbable()) && this.collides; // CraftBukkit ++ // Paper end - Climbing should not bypass cramming gamerule + } + + // CraftBukkit start - collidable API +diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java +index d8a2fbb33f4b77ffb1b3c928a369c2824ad815d7..60c2868f255d372226e0c1389caaa5477bbef41e 100644 +--- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java ++++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java +@@ -91,7 +91,7 @@ public class Bat extends AmbientCreature { + } + + @Override +- public boolean isPushable() { ++ public boolean isCollidable(boolean ignoreClimbing) { // Paper - Climbing should not bypass cramming gamerule + return false; + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Parrot.java b/src/main/java/net/minecraft/world/entity/animal/Parrot.java +index e9219921fe63a05bee4b6e18d5c1558cbcd88220..a2f0b79599799ad2aa85aff821d8ac76a8e650bd 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Parrot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Parrot.java +@@ -362,8 +362,8 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder -Date: Sun, 26 Jul 2020 14:44:09 +0200 -Subject: [PATCH] More lightning API - -== AT == -public net.minecraft.world.entity.LightningBolt life -public net.minecraft.world.entity.LightningBolt flashes - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java -index 0b2ba5c93355a5b7548d4634d964732e45477a34..6fed8075aa75e3852dc826a45ca44603c0446a56 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLightningStrike.java -@@ -66,4 +66,23 @@ public class CraftLightningStrike extends CraftEntity implements LightningStrike - return this.spigot; - } - // Spigot end -+ -+ // Paper start -+ @Override -+ public int getFlashCount() { -+ return getHandle().flashes; -+ } -+ -+ @Override -+ public void setFlashCount(int flashes) { -+ com.google.common.base.Preconditions.checkArgument(flashes >= 0, "Flashes has to be a positive number!"); -+ getHandle().flashes = flashes; -+ } -+ -+ @Override -+ public @org.jetbrains.annotations.Nullable org.bukkit.entity.Entity getCausingEntity() { -+ final var cause = this.getHandle().getCause(); -+ return cause == null ? null : cause.getBukkitEntity(); -+ } -+ // Paper end - } diff --git a/patches/server/0432-Add-missing-default-perms-for-commands.patch b/patches/server/0432-Add-missing-default-perms-for-commands.patch new file mode 100644 index 0000000000..95a842cb3f --- /dev/null +++ b/patches/server/0432-Add-missing-default-perms-for-commands.patch @@ -0,0 +1,178 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 16 Nov 2020 12:01:52 -0800 +Subject: [PATCH] Add missing default perms for commands + + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java +index a9ea2e38e4673686c9994a58c94ad19e59fd423c..b3169c551b8410f5861f9db0543c785439ecba7c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java +@@ -24,13 +24,76 @@ public final class CommandPermissions { + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "stop", "Allows the user to stop the server", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "list", "Allows the user to list all online players", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "gamemode", "Allows the user to change the gamemode of another player", PermissionDefault.OP, commands); +- DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "xp", "Allows the user to give themselves or others arbitrary values of experience", PermissionDefault.OP, commands); +- DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "toggledownfall", "Allows the user to toggle rain on/off for a given world", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "experience", "Allows the user to give themselves or others arbitrary values of experience", PermissionDefault.OP, commands); // Paper - wrong permission; redirects are de-redirected and the root literal name is used, so xp -> experience + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "defaultgamemode", "Allows the user to change the default gamemode of the server", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "seed", "Allows the user to view the seed of the world", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "effect", "Allows the user to add/remove effects on players", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "selector", "Allows the use of selectors", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "trigger", "Allows the use of the trigger command", PermissionDefault.TRUE, commands); ++ // Paper start ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "attribute", "Allows the user to query, add, remove or set an entity attribute", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "advancement", "Allows the user to give, remove, or check player advancements", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "ban", "Allows the user to add players to the ban list", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "ban-ip", "Allows the user to add ip address to the ban list", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "banlist", "Allows the user to display the ban list", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "bossbar", "Allows the user to create and modify bossbars", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "clear", "Allows the user to clear items from player inventory", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "clone", "Allows the user to copy blocks from one place to another", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "damage", "Allows the user to use the damage command to damage entities", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "data", "Allows the user to get, merge, modify, and remove block entity and entity NBT data", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "datapack", "Allows the user to control loaded data packs", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "debug", "Allows the user to start or stop a debugging session", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "deop", "Allows the user to revoke operator status from a player", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "difficulty", "Allows the user to set the difficulty level", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "enchant", "Allows the user to enchant a player item", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "execute", "Allows the user to execute another command", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "fill", "Allows the user to fill a region with a specific block", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "fillbiome", "Allows the user to fill a region with a specific biome", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "forceload", "Allows the user to force chunks to be constantly loaded or not", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "function", "Allows the user to run a function", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "gamerule", "Allows a user to set or query a game rule value", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "jfr", "Allows a user to use the vanilla Java FlightRecorder profiling system", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "locate", "Allows the user to locate the closest structure", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "loot", "Allows the user to drop items from an inventory slot onto the ground", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "op", "Allows the user to grant operator status to a player", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "pardon", "Allows the user to remove entries from the player ban list", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "pardon-ip", "Allows the user to remove entries from the ip address ban list", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "particle", "Allows the user to create particles", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "perf", "Allows the user to start/stop the vanilla performance metrics capture", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "playsound", "Allows the user to play a sound", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "ride", "Allows the user to use the /ride command to control passengers", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "recipe", "Allows the user to give or take recipes", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "reload", "Allows the user to reload loot tables, advancements, and functions from disk", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "item", "Allows the user to replace items in inventories", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "save-all", "Allows the user to save the server to disk", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "save-off", "Allows the user disable automatic server saves", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "save-on", "Allows the user enable automatic server saves", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "schedule", "Allows the user to delay the execution of a function", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "scoreboard", "Allows the user manage scoreboard objectives and players", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "setblock", "Allows the user to change a block to another block", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "setidletimeout", "Allows the user to set the time before idle players are kicked", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "setworldspawn", "Allows the user to set the world spawn", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "spawnpoint", "Allows the user to set the spawn point for a player", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "spectate", "Allows the user to make one player in spectator mode spectate an entity", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "spreadplayers", "Allows the user to teleport entities to random locations", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "stopsound", "Allows the user to stop a sound", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "summon", "Allows the user to summon an entity", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "tag", "Allows the user to control entity tags", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "team", "Allows the user to control teams", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "teammsg", "Allows the user to specify the message to send to team", PermissionDefault.TRUE, commands); // defaults to all players ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "tellraw", "Allows the user to display a JSON message to players", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "time", "Allows the user to change or query the world's game time", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "tick", "Allows the user to control the tick rate of the server", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "title", "Allows the user to manage screen titles", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "transfer", "Allows the user to transfer to another server", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "weather", "Allows the user to set the weather", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "whitelist", "Allows the user to manage the server whitelist", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "worldborder", "Allows the user to manage the world border", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "place", "Allows the user to place features and structures", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "return", "Allows the user to use the /return command", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "random", "Allows the user to generate a random number", PermissionDefault.OP, commands); ++ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "rotate", "Allows the user to change the rotation of entities", PermissionDefault.OP, commands); ++ // Paper end + + DefaultPermissions.registerPermission("minecraft.admin.command_feedback", "Receive command broadcasts when sendCommandFeedback is true", PermissionDefault.OP, commands); + +diff --git a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..75ed5050f72c001d6eab117a2c0b352a413548bd +--- /dev/null ++++ b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java +@@ -0,0 +1,83 @@ ++package io.papermc.paper.permissions; ++ ++import com.mojang.brigadier.tree.CommandNode; ++import com.mojang.brigadier.tree.RootCommandNode; ++import java.io.PrintStream; ++import java.util.HashSet; ++import java.util.LinkedHashSet; ++import java.util.List; ++import java.util.Set; ++import java.util.TreeSet; ++import net.minecraft.commands.CommandBuildContext; ++import net.minecraft.commands.CommandSourceStack; ++import net.minecraft.commands.Commands; ++import net.minecraft.server.Bootstrap; ++import net.minecraft.world.flag.FeatureFlags; ++import org.bukkit.Bukkit; ++import org.bukkit.craftbukkit.command.VanillaCommandWrapper; ++import org.bukkit.craftbukkit.util.permissions.CraftDefaultPermissions; ++import org.bukkit.permissions.Permission; ++import org.bukkit.support.RegistryHelper; ++import org.bukkit.support.environment.VanillaFeature; ++import org.junit.jupiter.api.AfterAll; ++import org.junit.jupiter.api.BeforeAll; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertTrue; ++ ++@VanillaFeature ++public class MinecraftCommandPermissionsTest { ++ ++ private static PrintStream old; ++ @BeforeAll ++ public static void before() { ++ old = System.out; ++ System.setOut(Bootstrap.STDOUT); ++ } ++ ++ @Test ++ public void test() { ++ CraftDefaultPermissions.registerCorePermissions(); ++ Set perms = collectMinecraftCommandPerms(); ++ ++ Commands commands = new Commands(Commands.CommandSelection.DEDICATED, CommandBuildContext.simple(RegistryHelper.getRegistry(), FeatureFlags.VANILLA_SET)); ++ RootCommandNode root = commands.getDispatcher().getRoot(); ++ Set missing = new LinkedHashSet<>(); ++ Set foundPerms = new HashSet<>(); ++ for (CommandNode child : root.getChildren()) { ++ final String vanillaPerm = VanillaCommandWrapper.getPermission(child); ++ if (!perms.contains(vanillaPerm)) { ++ missing.add("Missing permission for " + child.getName() + " (" + vanillaPerm + ") command"); ++ } else { ++ foundPerms.add(vanillaPerm); ++ } ++ } ++ assertTrue(missing.isEmpty(), "Commands missing permissions: \n" + String.join("\n", missing)); ++ perms.removeAll(foundPerms); ++ assertTrue(perms.isEmpty(), "Extra permissions not associated with a command: \n" + String.join("\n", perms)); ++ } ++ ++ private static final List TO_SKIP = List.of( ++ "minecraft.command.selector" ++ ); ++ ++ private static Set collectMinecraftCommandPerms() { ++ Set perms = new TreeSet<>(); ++ for (Permission perm : Bukkit.getPluginManager().getPermissions()) { ++ if (perm.getName().startsWith("minecraft.command.")) { ++ if (TO_SKIP.contains(perm.getName())) { ++ continue; ++ } ++ perms.add(perm.getName()); ++ } ++ } ++ return perms; ++ } ++ ++ @AfterAll ++ public static void after() { ++ if (old != null) { ++ System.setOut(old); ++ } ++ } ++} diff --git a/patches/server/0432-Climbing-should-not-bypass-cramming-gamerule.patch b/patches/server/0432-Climbing-should-not-bypass-cramming-gamerule.patch deleted file mode 100644 index ea3919bcb2..0000000000 --- a/patches/server/0432-Climbing-should-not-bypass-cramming-gamerule.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 23 Aug 2020 20:59:00 +0200 -Subject: [PATCH] Climbing should not bypass cramming gamerule - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 7609a58979388cb62be7ae94a51cc14774464214..fc40880fadb20f7c274c94b1e6a2fa6d0118e672 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2219,6 +2219,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public boolean isPushable() { -+ // Paper start - Climbing should not bypass cramming gamerule -+ return isCollidable(false); -+ } -+ -+ public boolean isCollidable(boolean ignoreClimbing) { -+ // Paper end - Climbing should not bypass cramming gamerule - return false; - } - -diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java -index b8d57e25851dd7da905100dfd4022e4b99fd7f02..721321a19ce056f82de2bef44a8791dc9d5b3418 100644 ---- a/src/main/java/net/minecraft/world/entity/EntitySelector.java -+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java -@@ -45,11 +45,16 @@ public final class EntitySelector { - } - - public static Predicate pushableBy(Entity entity) { -+ // Paper start - Climbing should not bypass cramming gamerule -+ return pushable(entity, false); -+ } -+ public static Predicate pushable(Entity entity, boolean ignoreClimbing) { -+ // Paper end - Climbing should not bypass cramming gamerule - PlayerTeam scoreboardteam = entity.getTeam(); - Team.CollisionRule scoreboardteambase_enumteampush = scoreboardteam == null ? Team.CollisionRule.ALWAYS : scoreboardteam.getCollisionRule(); - - return (Predicate) (scoreboardteambase_enumteampush == Team.CollisionRule.NEVER ? Predicates.alwaysFalse() : EntitySelector.NO_SPECTATORS.and((entity1) -> { -- if (!entity1.canCollideWithBukkit(entity) || !entity.canCollideWithBukkit(entity1)) { // CraftBukkit - collidable API -+ if (!entity1.isCollidable(ignoreClimbing) || !entity1.canCollideWithBukkit(entity) || !entity.canCollideWithBukkit(entity1)) { // CraftBukkit - collidable API // Paper - Climbing should not bypass cramming gamerule - return false; - } else if (entity1 instanceof Player && entity instanceof Player && !io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions) { // Paper - Configurable player collision - return false; -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index b742a42b2c86db79fb88399f40e8682afd600507..f025d36c8ae8606172e8166721f09c851784c3cc 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3722,7 +3722,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - return; - } - // Paper end - don't run getEntities if we're not going to use its result -- List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); -+ List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushable(this, this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule)); // Paper - Climbing should not bypass cramming gamerule - - if (!list.isEmpty()) { - // Paper - don't run getEntities if we're not going to use its result; moved up -@@ -3923,9 +3923,16 @@ public abstract class LivingEntity extends Entity implements Attackable { - return !this.isRemoved() && this.collides; // CraftBukkit - } - -+ // Paper start - Climbing should not bypass cramming gamerule - @Override - public boolean isPushable() { -- return this.isAlive() && !this.isSpectator() && !this.onClimbable() && this.collides; // CraftBukkit -+ return this.isCollidable(this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule); -+ } -+ -+ @Override -+ public boolean isCollidable(boolean ignoreClimbing) { -+ return this.isAlive() && !this.isSpectator() && (ignoreClimbing || !this.onClimbable()) && this.collides; // CraftBukkit -+ // Paper end - Climbing should not bypass cramming gamerule - } - - // CraftBukkit start - collidable API -diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index d8a2fbb33f4b77ffb1b3c928a369c2824ad815d7..60c2868f255d372226e0c1389caaa5477bbef41e 100644 ---- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java -+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -@@ -91,7 +91,7 @@ public class Bat extends AmbientCreature { - } - - @Override -- public boolean isPushable() { -+ public boolean isCollidable(boolean ignoreClimbing) { // Paper - Climbing should not bypass cramming gamerule - return false; - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Parrot.java b/src/main/java/net/minecraft/world/entity/animal/Parrot.java -index e9219921fe63a05bee4b6e18d5c1558cbcd88220..a2f0b79599799ad2aa85aff821d8ac76a8e650bd 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Parrot.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Parrot.java -@@ -362,8 +362,8 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder +Date: Thu, 27 Aug 2020 15:02:48 -0400 +Subject: [PATCH] Add PlayerShearBlockEvent + + +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 c913d45704e4eb3a0aa322d3f5f83eec6c147051..4ec03b15bb8a82d92fcb2b7fef70e3c7087a9b68 100644 +--- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java +@@ -141,7 +141,7 @@ public class BeehiveBlock extends BaseEntityBlock { + } + + public static void dropHoneycomb(Level world, BlockPos pos) { +- popResource(world, pos, new ItemStack(Items.HONEYCOMB, 3)); ++ popResource(world, pos, new ItemStack(Items.HONEYCOMB, 3)); // Paper - Add PlayerShearBlockEvent; conflict on change, item needs to be set below + } + + @Override +@@ -153,8 +153,19 @@ public class BeehiveBlock extends BaseEntityBlock { + Item item = stack.getItem(); + + if (stack.is(Items.SHEARS)) { ++ // Paper start - Add PlayerShearBlockEvent ++ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), new java.util.ArrayList<>()); ++ event.getDrops().add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(Items.HONEYCOMB, 3))); ++ if (!event.callEvent()) { ++ return InteractionResult.PASS; ++ } ++ // Paper end + world.playSound(player, player.getX(), player.getY(), player.getZ(), SoundEvents.BEEHIVE_SHEAR, SoundSource.BLOCKS, 1.0F, 1.0F); +- BeehiveBlock.dropHoneycomb(world, pos); ++ // Paper start - Add PlayerShearBlockEvent ++ for (org.bukkit.inventory.ItemStack itemDrop : event.getDrops()) { ++ popResource(world, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(itemDrop)); ++ } ++ // Paper end - Add PlayerShearBlockEvent + stack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand)); + flag = true; + world.gameEvent((Entity) player, (Holder) GameEvent.SHEAR, pos); +diff --git a/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java b/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java +index dad7a610286b0ab6b916a6169fa8f6f641deb39a..2b43c77d5aa609d4716df827cefcf008dfd13a06 100644 +--- a/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java +@@ -38,16 +38,24 @@ public class PumpkinBlock extends Block { + } else if (world.isClientSide) { + return InteractionResult.SUCCESS; + } else { ++ // Paper start - Add PlayerShearBlockEvent ++ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), new java.util.ArrayList<>()); ++ event.getDrops().add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(Items.PUMPKIN_SEEDS, 4))); ++ if (!event.callEvent()) { ++ return InteractionResult.PASS; ++ } ++ // Paper end - Add PlayerShearBlockEvent + Direction direction = hit.getDirection(); + Direction direction2 = direction.getAxis() == Direction.Axis.Y ? player.getDirection().getOpposite() : direction; + world.playSound(null, pos, SoundEvents.PUMPKIN_CARVE, SoundSource.BLOCKS, 1.0F, 1.0F); + world.setBlock(pos, Blocks.CARVED_PUMPKIN.defaultBlockState().setValue(CarvedPumpkinBlock.FACING, direction2), 11); ++ for (org.bukkit.inventory.ItemStack item : event.getDrops()) { // Paper - Add PlayerShearBlockEvent + ItemEntity itemEntity = new ItemEntity( + world, + (double)pos.getX() + 0.5 + (double)direction2.getStepX() * 0.65, + (double)pos.getY() + 0.1, + (double)pos.getZ() + 0.5 + (double)direction2.getStepZ() * 0.65, +- new ItemStack(Items.PUMPKIN_SEEDS, 4) ++ org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item) // Paper - Add PlayerShearBlockEvent + ); + itemEntity.setDeltaMovement( + 0.05 * (double)direction2.getStepX() + world.random.nextDouble() * 0.02, +@@ -55,6 +63,7 @@ public class PumpkinBlock extends Block { + 0.05 * (double)direction2.getStepZ() + world.random.nextDouble() * 0.02 + ); + world.addFreshEntity(itemEntity); ++ } // Paper - Add PlayerShearBlockEvent + stack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand)); + world.gameEvent(player, GameEvent.SHEAR, pos); + player.awardStat(Stats.ITEM_USED.get(Items.SHEARS)); diff --git a/patches/server/0433-Add-missing-default-perms-for-commands.patch b/patches/server/0433-Add-missing-default-perms-for-commands.patch deleted file mode 100644 index 95a842cb3f..0000000000 --- a/patches/server/0433-Add-missing-default-perms-for-commands.patch +++ /dev/null @@ -1,178 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 16 Nov 2020 12:01:52 -0800 -Subject: [PATCH] Add missing default perms for commands - - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java -index a9ea2e38e4673686c9994a58c94ad19e59fd423c..b3169c551b8410f5861f9db0543c785439ecba7c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java -@@ -24,13 +24,76 @@ public final class CommandPermissions { - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "stop", "Allows the user to stop the server", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "list", "Allows the user to list all online players", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "gamemode", "Allows the user to change the gamemode of another player", PermissionDefault.OP, commands); -- DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "xp", "Allows the user to give themselves or others arbitrary values of experience", PermissionDefault.OP, commands); -- DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "toggledownfall", "Allows the user to toggle rain on/off for a given world", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "experience", "Allows the user to give themselves or others arbitrary values of experience", PermissionDefault.OP, commands); // Paper - wrong permission; redirects are de-redirected and the root literal name is used, so xp -> experience - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "defaultgamemode", "Allows the user to change the default gamemode of the server", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "seed", "Allows the user to view the seed of the world", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "effect", "Allows the user to add/remove effects on players", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "selector", "Allows the use of selectors", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "trigger", "Allows the use of the trigger command", PermissionDefault.TRUE, commands); -+ // Paper start -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "attribute", "Allows the user to query, add, remove or set an entity attribute", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "advancement", "Allows the user to give, remove, or check player advancements", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "ban", "Allows the user to add players to the ban list", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "ban-ip", "Allows the user to add ip address to the ban list", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "banlist", "Allows the user to display the ban list", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "bossbar", "Allows the user to create and modify bossbars", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "clear", "Allows the user to clear items from player inventory", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "clone", "Allows the user to copy blocks from one place to another", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "damage", "Allows the user to use the damage command to damage entities", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "data", "Allows the user to get, merge, modify, and remove block entity and entity NBT data", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "datapack", "Allows the user to control loaded data packs", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "debug", "Allows the user to start or stop a debugging session", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "deop", "Allows the user to revoke operator status from a player", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "difficulty", "Allows the user to set the difficulty level", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "enchant", "Allows the user to enchant a player item", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "execute", "Allows the user to execute another command", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "fill", "Allows the user to fill a region with a specific block", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "fillbiome", "Allows the user to fill a region with a specific biome", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "forceload", "Allows the user to force chunks to be constantly loaded or not", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "function", "Allows the user to run a function", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "gamerule", "Allows a user to set or query a game rule value", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "jfr", "Allows a user to use the vanilla Java FlightRecorder profiling system", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "locate", "Allows the user to locate the closest structure", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "loot", "Allows the user to drop items from an inventory slot onto the ground", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "op", "Allows the user to grant operator status to a player", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "pardon", "Allows the user to remove entries from the player ban list", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "pardon-ip", "Allows the user to remove entries from the ip address ban list", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "particle", "Allows the user to create particles", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "perf", "Allows the user to start/stop the vanilla performance metrics capture", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "playsound", "Allows the user to play a sound", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "ride", "Allows the user to use the /ride command to control passengers", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "recipe", "Allows the user to give or take recipes", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "reload", "Allows the user to reload loot tables, advancements, and functions from disk", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "item", "Allows the user to replace items in inventories", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "save-all", "Allows the user to save the server to disk", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "save-off", "Allows the user disable automatic server saves", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "save-on", "Allows the user enable automatic server saves", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "schedule", "Allows the user to delay the execution of a function", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "scoreboard", "Allows the user manage scoreboard objectives and players", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "setblock", "Allows the user to change a block to another block", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "setidletimeout", "Allows the user to set the time before idle players are kicked", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "setworldspawn", "Allows the user to set the world spawn", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "spawnpoint", "Allows the user to set the spawn point for a player", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "spectate", "Allows the user to make one player in spectator mode spectate an entity", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "spreadplayers", "Allows the user to teleport entities to random locations", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "stopsound", "Allows the user to stop a sound", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "summon", "Allows the user to summon an entity", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "tag", "Allows the user to control entity tags", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "team", "Allows the user to control teams", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "teammsg", "Allows the user to specify the message to send to team", PermissionDefault.TRUE, commands); // defaults to all players -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "tellraw", "Allows the user to display a JSON message to players", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "time", "Allows the user to change or query the world's game time", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "tick", "Allows the user to control the tick rate of the server", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "title", "Allows the user to manage screen titles", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "transfer", "Allows the user to transfer to another server", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "weather", "Allows the user to set the weather", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "whitelist", "Allows the user to manage the server whitelist", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "worldborder", "Allows the user to manage the world border", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "place", "Allows the user to place features and structures", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "return", "Allows the user to use the /return command", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "random", "Allows the user to generate a random number", PermissionDefault.OP, commands); -+ DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "rotate", "Allows the user to change the rotation of entities", PermissionDefault.OP, commands); -+ // Paper end - - DefaultPermissions.registerPermission("minecraft.admin.command_feedback", "Receive command broadcasts when sendCommandFeedback is true", PermissionDefault.OP, commands); - -diff --git a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..75ed5050f72c001d6eab117a2c0b352a413548bd ---- /dev/null -+++ b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java -@@ -0,0 +1,83 @@ -+package io.papermc.paper.permissions; -+ -+import com.mojang.brigadier.tree.CommandNode; -+import com.mojang.brigadier.tree.RootCommandNode; -+import java.io.PrintStream; -+import java.util.HashSet; -+import java.util.LinkedHashSet; -+import java.util.List; -+import java.util.Set; -+import java.util.TreeSet; -+import net.minecraft.commands.CommandBuildContext; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.commands.Commands; -+import net.minecraft.server.Bootstrap; -+import net.minecraft.world.flag.FeatureFlags; -+import org.bukkit.Bukkit; -+import org.bukkit.craftbukkit.command.VanillaCommandWrapper; -+import org.bukkit.craftbukkit.util.permissions.CraftDefaultPermissions; -+import org.bukkit.permissions.Permission; -+import org.bukkit.support.RegistryHelper; -+import org.bukkit.support.environment.VanillaFeature; -+import org.junit.jupiter.api.AfterAll; -+import org.junit.jupiter.api.BeforeAll; -+import org.junit.jupiter.api.Test; -+ -+import static org.junit.jupiter.api.Assertions.assertTrue; -+ -+@VanillaFeature -+public class MinecraftCommandPermissionsTest { -+ -+ private static PrintStream old; -+ @BeforeAll -+ public static void before() { -+ old = System.out; -+ System.setOut(Bootstrap.STDOUT); -+ } -+ -+ @Test -+ public void test() { -+ CraftDefaultPermissions.registerCorePermissions(); -+ Set perms = collectMinecraftCommandPerms(); -+ -+ Commands commands = new Commands(Commands.CommandSelection.DEDICATED, CommandBuildContext.simple(RegistryHelper.getRegistry(), FeatureFlags.VANILLA_SET)); -+ RootCommandNode root = commands.getDispatcher().getRoot(); -+ Set missing = new LinkedHashSet<>(); -+ Set foundPerms = new HashSet<>(); -+ for (CommandNode child : root.getChildren()) { -+ final String vanillaPerm = VanillaCommandWrapper.getPermission(child); -+ if (!perms.contains(vanillaPerm)) { -+ missing.add("Missing permission for " + child.getName() + " (" + vanillaPerm + ") command"); -+ } else { -+ foundPerms.add(vanillaPerm); -+ } -+ } -+ assertTrue(missing.isEmpty(), "Commands missing permissions: \n" + String.join("\n", missing)); -+ perms.removeAll(foundPerms); -+ assertTrue(perms.isEmpty(), "Extra permissions not associated with a command: \n" + String.join("\n", perms)); -+ } -+ -+ private static final List TO_SKIP = List.of( -+ "minecraft.command.selector" -+ ); -+ -+ private static Set collectMinecraftCommandPerms() { -+ Set perms = new TreeSet<>(); -+ for (Permission perm : Bukkit.getPluginManager().getPermissions()) { -+ if (perm.getName().startsWith("minecraft.command.")) { -+ if (TO_SKIP.contains(perm.getName())) { -+ continue; -+ } -+ perms.add(perm.getName()); -+ } -+ } -+ return perms; -+ } -+ -+ @AfterAll -+ public static void after() { -+ if (old != null) { -+ System.setOut(old); -+ } -+ } -+} diff --git a/patches/server/0434-Add-PlayerShearBlockEvent.patch b/patches/server/0434-Add-PlayerShearBlockEvent.patch deleted file mode 100644 index dc2dd37c19..0000000000 --- a/patches/server/0434-Add-PlayerShearBlockEvent.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Thu, 27 Aug 2020 15:02:48 -0400 -Subject: [PATCH] Add PlayerShearBlockEvent - - -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 c913d45704e4eb3a0aa322d3f5f83eec6c147051..4ec03b15bb8a82d92fcb2b7fef70e3c7087a9b68 100644 ---- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java -@@ -141,7 +141,7 @@ public class BeehiveBlock extends BaseEntityBlock { - } - - public static void dropHoneycomb(Level world, BlockPos pos) { -- popResource(world, pos, new ItemStack(Items.HONEYCOMB, 3)); -+ popResource(world, pos, new ItemStack(Items.HONEYCOMB, 3)); // Paper - Add PlayerShearBlockEvent; conflict on change, item needs to be set below - } - - @Override -@@ -153,8 +153,19 @@ public class BeehiveBlock extends BaseEntityBlock { - Item item = stack.getItem(); - - if (stack.is(Items.SHEARS)) { -+ // Paper start - Add PlayerShearBlockEvent -+ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), new java.util.ArrayList<>()); -+ event.getDrops().add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(Items.HONEYCOMB, 3))); -+ if (!event.callEvent()) { -+ return InteractionResult.PASS; -+ } -+ // Paper end - world.playSound(player, player.getX(), player.getY(), player.getZ(), SoundEvents.BEEHIVE_SHEAR, SoundSource.BLOCKS, 1.0F, 1.0F); -- BeehiveBlock.dropHoneycomb(world, pos); -+ // Paper start - Add PlayerShearBlockEvent -+ for (org.bukkit.inventory.ItemStack itemDrop : event.getDrops()) { -+ popResource(world, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(itemDrop)); -+ } -+ // Paper end - Add PlayerShearBlockEvent - stack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand)); - flag = true; - world.gameEvent((Entity) player, (Holder) GameEvent.SHEAR, pos); -diff --git a/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java b/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java -index dad7a610286b0ab6b916a6169fa8f6f641deb39a..2b43c77d5aa609d4716df827cefcf008dfd13a06 100644 ---- a/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java -@@ -38,16 +38,24 @@ public class PumpkinBlock extends Block { - } else if (world.isClientSide) { - return InteractionResult.SUCCESS; - } else { -+ // Paper start - Add PlayerShearBlockEvent -+ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), new java.util.ArrayList<>()); -+ event.getDrops().add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(Items.PUMPKIN_SEEDS, 4))); -+ if (!event.callEvent()) { -+ return InteractionResult.PASS; -+ } -+ // Paper end - Add PlayerShearBlockEvent - Direction direction = hit.getDirection(); - Direction direction2 = direction.getAxis() == Direction.Axis.Y ? player.getDirection().getOpposite() : direction; - world.playSound(null, pos, SoundEvents.PUMPKIN_CARVE, SoundSource.BLOCKS, 1.0F, 1.0F); - world.setBlock(pos, Blocks.CARVED_PUMPKIN.defaultBlockState().setValue(CarvedPumpkinBlock.FACING, direction2), 11); -+ for (org.bukkit.inventory.ItemStack item : event.getDrops()) { // Paper - Add PlayerShearBlockEvent - ItemEntity itemEntity = new ItemEntity( - world, - (double)pos.getX() + 0.5 + (double)direction2.getStepX() * 0.65, - (double)pos.getY() + 0.1, - (double)pos.getZ() + 0.5 + (double)direction2.getStepZ() * 0.65, -- new ItemStack(Items.PUMPKIN_SEEDS, 4) -+ org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item) // Paper - Add PlayerShearBlockEvent - ); - itemEntity.setDeltaMovement( - 0.05 * (double)direction2.getStepX() + world.random.nextDouble() * 0.02, -@@ -55,6 +63,7 @@ public class PumpkinBlock extends Block { - 0.05 * (double)direction2.getStepZ() + world.random.nextDouble() * 0.02 - ); - world.addFreshEntity(itemEntity); -+ } // Paper - Add PlayerShearBlockEvent - stack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand)); - world.gameEvent(player, GameEvent.SHEAR, pos); - player.awardStat(Stats.ITEM_USED.get(Items.SHEARS)); diff --git a/patches/server/0434-Limit-recipe-packets.patch b/patches/server/0434-Limit-recipe-packets.patch new file mode 100644 index 0000000000..39de7be41f --- /dev/null +++ b/patches/server/0434-Limit-recipe-packets.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sat, 12 Dec 2020 23:45:28 +0000 +Subject: [PATCH] Limit recipe packets + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 1e6c8a23e892fc1c49da9538b435aa3eb0a28934..04de96af5415c3115703f5ab42e9fa3aa2ccee60 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -279,6 +279,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + private final TickThrottler chatSpamThrottler = new TickThrottler(20, 200); + private final TickThrottler tabSpamThrottler = new TickThrottler(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement, io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit); // Paper - configurable tab spam limits + private final TickThrottler dropSpamThrottler = new TickThrottler(20, 1480); ++ private final TickThrottler recipeSpamPackets = new TickThrottler(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement, io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit); + private double firstGoodX; + private double firstGoodY; + private double firstGoodZ; +@@ -395,6 +396,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.keepConnectionAlive(); + this.chatSpamThrottler.tick(); + this.tabSpamThrottler.tick(); // Paper - configurable tab spam limits ++ this.recipeSpamPackets.tick(); // Paper - auto recipe limit + this.dropSpamThrottler.tick(); + if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { + this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 +@@ -3155,6 +3157,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + @Override + public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { ++ // Paper start - auto recipe limit ++ if (!org.bukkit.Bukkit.isPrimaryThread()) { ++ if (!this.recipeSpamPackets.isIncrementAndUnderThreshold()) { ++ this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam")); ++ return; ++ } ++ } ++ // Paper end - auto recipe limit + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + this.player.resetLastActionTime(); + if (!this.player.isSpectator() && this.player.containerMenu.containerId == packet.containerId()) { diff --git a/patches/server/0435-Fix-CraftSound-backwards-compatibility.patch b/patches/server/0435-Fix-CraftSound-backwards-compatibility.patch new file mode 100644 index 0000000000..604e24920d --- /dev/null +++ b/patches/server/0435-Fix-CraftSound-backwards-compatibility.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 17 Dec 2020 15:25:49 -0600 +Subject: [PATCH] Fix CraftSound backwards compatibility + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftSound.java b/src/main/java/org/bukkit/craftbukkit/CraftSound.java +index e53d6d33bfe9ed14fce0f5df0ab7648f18489c39..5b6e6902db19b078bb8598014a87c06f1267acc4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftSound.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftSound.java +@@ -106,4 +106,10 @@ public class CraftSound implements Sound, Handleable { + public int hashCode() { + return this.getKey().hashCode(); + } ++ ++ // Paper start ++ public static String getSound(Sound sound) { ++ return sound.getKey().getKey(); ++ } ++ // Paper end + } diff --git a/patches/server/0435-Limit-recipe-packets.patch b/patches/server/0435-Limit-recipe-packets.patch deleted file mode 100644 index 39de7be41f..0000000000 --- a/patches/server/0435-Limit-recipe-packets.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sat, 12 Dec 2020 23:45:28 +0000 -Subject: [PATCH] Limit recipe packets - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 1e6c8a23e892fc1c49da9538b435aa3eb0a28934..04de96af5415c3115703f5ab42e9fa3aa2ccee60 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -279,6 +279,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - private final TickThrottler chatSpamThrottler = new TickThrottler(20, 200); - private final TickThrottler tabSpamThrottler = new TickThrottler(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement, io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit); // Paper - configurable tab spam limits - private final TickThrottler dropSpamThrottler = new TickThrottler(20, 1480); -+ private final TickThrottler recipeSpamPackets = new TickThrottler(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement, io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit); - private double firstGoodX; - private double firstGoodY; - private double firstGoodZ; -@@ -395,6 +396,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.keepConnectionAlive(); - this.chatSpamThrottler.tick(); - this.tabSpamThrottler.tick(); // Paper - configurable tab spam limits -+ this.recipeSpamPackets.tick(); // Paper - auto recipe limit - this.dropSpamThrottler.tick(); - if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { - this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 -@@ -3155,6 +3157,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - @Override - public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { -+ // Paper start - auto recipe limit -+ if (!org.bukkit.Bukkit.isPrimaryThread()) { -+ if (!this.recipeSpamPackets.isIncrementAndUnderThreshold()) { -+ this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam")); -+ return; -+ } -+ } -+ // Paper end - auto recipe limit - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); - this.player.resetLastActionTime(); - if (!this.player.isSpectator() && this.player.containerMenu.containerId == packet.containerId()) { diff --git a/patches/server/0436-Fix-CraftSound-backwards-compatibility.patch b/patches/server/0436-Fix-CraftSound-backwards-compatibility.patch deleted file mode 100644 index 604e24920d..0000000000 --- a/patches/server/0436-Fix-CraftSound-backwards-compatibility.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Thu, 17 Dec 2020 15:25:49 -0600 -Subject: [PATCH] Fix CraftSound backwards compatibility - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftSound.java b/src/main/java/org/bukkit/craftbukkit/CraftSound.java -index e53d6d33bfe9ed14fce0f5df0ab7648f18489c39..5b6e6902db19b078bb8598014a87c06f1267acc4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftSound.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftSound.java -@@ -106,4 +106,10 @@ public class CraftSound implements Sound, Handleable { - public int hashCode() { - return this.getKey().hashCode(); - } -+ -+ // Paper start -+ public static String getSound(Sound sound) { -+ return sound.getKey().getKey(); -+ } -+ // Paper end - } diff --git a/patches/server/0436-Player-Chunk-Load-Unload-Events.patch b/patches/server/0436-Player-Chunk-Load-Unload-Events.patch new file mode 100644 index 0000000000..0fee853cd3 --- /dev/null +++ b/patches/server/0436-Player-Chunk-Load-Unload-Events.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: ysl3000 +Date: Mon, 5 Oct 2020 21:25:16 +0200 +Subject: [PATCH] Player Chunk Load/Unload Events + + +diff --git a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java +index 7c4b795b8a0f58dd07bc5acb1e309476bf4cbe90..cdd66e6ce96e2613afe7f06ca8da3cfaa6704b2d 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java ++++ b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java +@@ -44,6 +44,11 @@ public class PlayerChunkSender { + public void dropChunk(ServerPlayer player, ChunkPos pos) { + if (!this.pendingChunks.remove(pos.toLong()) && player.isAlive()) { + player.connection.send(new ClientboundForgetLevelChunkPacket(pos)); ++ // Paper start - PlayerChunkUnloadEvent ++ if (io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0) { ++ new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(pos.longKey), player.getBukkitEntity()).callEvent(); ++ } ++ // Paper end - PlayerChunkUnloadEvent + } + } + +@@ -75,6 +80,11 @@ public class PlayerChunkSender { + + private static void sendChunk(ServerGamePacketListenerImpl handler, ServerLevel world, LevelChunk chunk) { + handler.send(new ClientboundLevelChunkWithLightPacket(chunk, world.getLightEngine(), null, null)); ++ // Paper start - PlayerChunkLoadEvent ++ if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { ++ new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), handler.getPlayer().getBukkitEntity()).callEvent(); ++ } ++ // Paper end - PlayerChunkLoadEvent + ChunkPos chunkPos = chunk.getPos(); + DebugPackets.sendPoiPacketsForChunk(world, chunkPos); + } diff --git a/patches/server/0437-Optimize-Dynamic-get-Missing-Keys.patch b/patches/server/0437-Optimize-Dynamic-get-Missing-Keys.patch new file mode 100644 index 0000000000..e8bbac8b76 --- /dev/null +++ b/patches/server/0437-Optimize-Dynamic-get-Missing-Keys.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 21 Dec 2020 11:01:42 -0500 +Subject: [PATCH] Optimize Dynamic#get Missing Keys + +get was calling toString() on every NBT object that was ever asked for an optional +key from the object to build a string for the error text. + +When done on large NBT objects, this was using a ton of computation time building the +JSON representation of the NBT object. + +Now we will just skip the value when 99.9999% of the time the text is never even printed. + +diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java +index d73bb05272d69471644b28f8c704a3bfceca72c2..8b4ea53b891bb7a5ceb791c4afaaf33814d9b6f6 100644 +--- a/src/main/java/com/mojang/serialization/Dynamic.java ++++ b/src/main/java/com/mojang/serialization/Dynamic.java +@@ -19,6 +19,7 @@ import java.util.stream.Stream; + + @SuppressWarnings("unused") + public class Dynamic extends DynamicLike { ++ private static final boolean DEBUG_MISSING_KEYS = Boolean.getBoolean("Paper.debugDynamicMissingKeys"); // Paper - Perf: Skip toString on values like NBT + private final T value; + + public Dynamic(final DynamicOps ops) { +@@ -120,7 +121,7 @@ public class Dynamic extends DynamicLike { + return new OptionalDynamic<>(ops, ops.getMap(value).flatMap(m -> { + final T value = m.get(key); + if (value == null) { +- return DataResult.error(() -> "key missing: " + key + " in " + this.value); ++ return DataResult.error(() -> DEBUG_MISSING_KEYS ? "key missing: " + key + " in " + this.value : "key missing: " + key); // Paper - Perf: Skip toString on values like NBT + } + return DataResult.success(new Dynamic<>(ops, value)); + })); diff --git a/patches/server/0437-Player-Chunk-Load-Unload-Events.patch b/patches/server/0437-Player-Chunk-Load-Unload-Events.patch deleted file mode 100644 index 0fee853cd3..0000000000 --- a/patches/server/0437-Player-Chunk-Load-Unload-Events.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: ysl3000 -Date: Mon, 5 Oct 2020 21:25:16 +0200 -Subject: [PATCH] Player Chunk Load/Unload Events - - -diff --git a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java -index 7c4b795b8a0f58dd07bc5acb1e309476bf4cbe90..cdd66e6ce96e2613afe7f06ca8da3cfaa6704b2d 100644 ---- a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java -+++ b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java -@@ -44,6 +44,11 @@ public class PlayerChunkSender { - public void dropChunk(ServerPlayer player, ChunkPos pos) { - if (!this.pendingChunks.remove(pos.toLong()) && player.isAlive()) { - player.connection.send(new ClientboundForgetLevelChunkPacket(pos)); -+ // Paper start - PlayerChunkUnloadEvent -+ if (io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(pos.longKey), player.getBukkitEntity()).callEvent(); -+ } -+ // Paper end - PlayerChunkUnloadEvent - } - } - -@@ -75,6 +80,11 @@ public class PlayerChunkSender { - - private static void sendChunk(ServerGamePacketListenerImpl handler, ServerLevel world, LevelChunk chunk) { - handler.send(new ClientboundLevelChunkWithLightPacket(chunk, world.getLightEngine(), null, null)); -+ // Paper start - PlayerChunkLoadEvent -+ if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), handler.getPlayer().getBukkitEntity()).callEvent(); -+ } -+ // Paper end - PlayerChunkLoadEvent - ChunkPos chunkPos = chunk.getPos(); - DebugPackets.sendPoiPacketsForChunk(world, chunkPos); - } diff --git a/patches/server/0438-Expose-LivingEntity-hurt-direction.patch b/patches/server/0438-Expose-LivingEntity-hurt-direction.patch new file mode 100644 index 0000000000..3720327ae5 --- /dev/null +++ b/patches/server/0438-Expose-LivingEntity-hurt-direction.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Vainomaa +Date: Sun, 13 Dec 2020 05:32:05 +0200 +Subject: [PATCH] Expose LivingEntity hurt direction + + +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 c23b8f00d7ce3a46f9d104ffae5e4c6124a111ce..136a6b8e2065c7bada396e0f54f91c841a85c3d8 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -191,7 +191,7 @@ public abstract class Player extends LivingEntity { + private Optional lastDeathLocation; + @Nullable + public FishingHook fishing; +- protected float hurtDir; ++ public float hurtDir; // Paper - protected -> public + @Nullable + public Vec3 currentImpulseImpactPos; + @Nullable +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +index 8012ee71e1ce9f174eb5c4ac9eb8372b81e0a78c..42c41cd4b280839a35f77e04d0dc6a06d262d8f3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -125,6 +125,13 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + } + } + ++ // Paper start ++ @Override ++ public void setHurtDirection(float hurtDirection) { ++ this.getHandle().hurtDir = hurtDirection; ++ } ++ // Paper end ++ + @Override + public int getSleepTicks() { + return this.getHandle().sleepCounter; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index c19694876007f711dfdcf58ef435a839b1e31d72..1ca252f36500322d56c0c12b6ec80c069214c0e8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -1024,4 +1024,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + this.getHandle().take(((CraftItem) item).getHandle(), quantity); + } + // Paper end - pickup animation API ++ ++ // Paper start - hurt direction API ++ @Override ++ public float getHurtDirection() { ++ return this.getHandle().getHurtDir(); ++ } ++ ++ @Override ++ public void setHurtDirection(final float hurtDirection) { ++ throw new UnsupportedOperationException("Cannot set the hurt direction on a non player"); ++ } ++ // Paper end - hurt direction API + } diff --git a/patches/server/0438-Optimize-Dynamic-get-Missing-Keys.patch b/patches/server/0438-Optimize-Dynamic-get-Missing-Keys.patch deleted file mode 100644 index e8bbac8b76..0000000000 --- a/patches/server/0438-Optimize-Dynamic-get-Missing-Keys.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 21 Dec 2020 11:01:42 -0500 -Subject: [PATCH] Optimize Dynamic#get Missing Keys - -get was calling toString() on every NBT object that was ever asked for an optional -key from the object to build a string for the error text. - -When done on large NBT objects, this was using a ton of computation time building the -JSON representation of the NBT object. - -Now we will just skip the value when 99.9999% of the time the text is never even printed. - -diff --git a/src/main/java/com/mojang/serialization/Dynamic.java b/src/main/java/com/mojang/serialization/Dynamic.java -index d73bb05272d69471644b28f8c704a3bfceca72c2..8b4ea53b891bb7a5ceb791c4afaaf33814d9b6f6 100644 ---- a/src/main/java/com/mojang/serialization/Dynamic.java -+++ b/src/main/java/com/mojang/serialization/Dynamic.java -@@ -19,6 +19,7 @@ import java.util.stream.Stream; - - @SuppressWarnings("unused") - public class Dynamic extends DynamicLike { -+ private static final boolean DEBUG_MISSING_KEYS = Boolean.getBoolean("Paper.debugDynamicMissingKeys"); // Paper - Perf: Skip toString on values like NBT - private final T value; - - public Dynamic(final DynamicOps ops) { -@@ -120,7 +121,7 @@ public class Dynamic extends DynamicLike { - return new OptionalDynamic<>(ops, ops.getMap(value).flatMap(m -> { - final T value = m.get(key); - if (value == null) { -- return DataResult.error(() -> "key missing: " + key + " in " + this.value); -+ return DataResult.error(() -> DEBUG_MISSING_KEYS ? "key missing: " + key + " in " + this.value : "key missing: " + key); // Paper - Perf: Skip toString on values like NBT - } - return DataResult.success(new Dynamic<>(ops, value)); - })); diff --git a/patches/server/0439-Add-OBSTRUCTED-reason-to-BedEnterResult.patch b/patches/server/0439-Add-OBSTRUCTED-reason-to-BedEnterResult.patch new file mode 100644 index 0000000000..675b673d78 --- /dev/null +++ b/patches/server/0439-Add-OBSTRUCTED-reason-to-BedEnterResult.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 24 Dec 2020 12:43:39 -0800 +Subject: [PATCH] Add OBSTRUCTED reason to BedEnterResult + + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 798a608784d4880f8d8e77960cfaf27700d06ddb..f8751bf07479d6619ec1acb19f84a9af00ecd308 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -312,6 +312,10 @@ public class CraftEventFactory { + return BedEnterResult.TOO_FAR_AWAY; + case NOT_SAFE: + return BedEnterResult.NOT_SAFE; ++ // Paper start ++ case OBSTRUCTED: ++ return BedEnterResult.OBSTRUCTED; ++ // Paper end + default: + return BedEnterResult.OTHER_PROBLEM; + } diff --git a/patches/server/0439-Expose-LivingEntity-hurt-direction.patch b/patches/server/0439-Expose-LivingEntity-hurt-direction.patch deleted file mode 100644 index 3720327ae5..0000000000 --- a/patches/server/0439-Expose-LivingEntity-hurt-direction.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Sun, 13 Dec 2020 05:32:05 +0200 -Subject: [PATCH] Expose LivingEntity hurt direction - - -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 c23b8f00d7ce3a46f9d104ffae5e4c6124a111ce..136a6b8e2065c7bada396e0f54f91c841a85c3d8 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -191,7 +191,7 @@ public abstract class Player extends LivingEntity { - private Optional lastDeathLocation; - @Nullable - public FishingHook fishing; -- protected float hurtDir; -+ public float hurtDir; // Paper - protected -> public - @Nullable - public Vec3 currentImpulseImpactPos; - @Nullable -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 8012ee71e1ce9f174eb5c4ac9eb8372b81e0a78c..42c41cd4b280839a35f77e04d0dc6a06d262d8f3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -125,6 +125,13 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - } - } - -+ // Paper start -+ @Override -+ public void setHurtDirection(float hurtDirection) { -+ this.getHandle().hurtDir = hurtDirection; -+ } -+ // Paper end -+ - @Override - public int getSleepTicks() { - return this.getHandle().sleepCounter; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index c19694876007f711dfdcf58ef435a839b1e31d72..1ca252f36500322d56c0c12b6ec80c069214c0e8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -1024,4 +1024,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - this.getHandle().take(((CraftItem) item).getHandle(), quantity); - } - // Paper end - pickup animation API -+ -+ // Paper start - hurt direction API -+ @Override -+ public float getHurtDirection() { -+ return this.getHandle().getHurtDir(); -+ } -+ -+ @Override -+ public void setHurtDirection(final float hurtDirection) { -+ throw new UnsupportedOperationException("Cannot set the hurt direction on a non player"); -+ } -+ // Paper end - hurt direction API - } diff --git a/patches/server/0440-Add-OBSTRUCTED-reason-to-BedEnterResult.patch b/patches/server/0440-Add-OBSTRUCTED-reason-to-BedEnterResult.patch deleted file mode 100644 index 675b673d78..0000000000 --- a/patches/server/0440-Add-OBSTRUCTED-reason-to-BedEnterResult.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 24 Dec 2020 12:43:39 -0800 -Subject: [PATCH] Add OBSTRUCTED reason to BedEnterResult - - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 798a608784d4880f8d8e77960cfaf27700d06ddb..f8751bf07479d6619ec1acb19f84a9af00ecd308 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -312,6 +312,10 @@ public class CraftEventFactory { - return BedEnterResult.TOO_FAR_AWAY; - case NOT_SAFE: - return BedEnterResult.NOT_SAFE; -+ // Paper start -+ case OBSTRUCTED: -+ return BedEnterResult.OBSTRUCTED; -+ // Paper end - default: - return BedEnterResult.OTHER_PROBLEM; - } diff --git a/patches/server/0440-Fix-crash-from-invalid-ingredient-lists-in-VillagerA.patch b/patches/server/0440-Fix-crash-from-invalid-ingredient-lists-in-VillagerA.patch new file mode 100644 index 0000000000..3122449eed --- /dev/null +++ b/patches/server/0440-Fix-crash-from-invalid-ingredient-lists-in-VillagerA.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sun, 27 Dec 2020 11:31:06 +0000 +Subject: [PATCH] Fix crash from invalid ingredient lists in + VillagerAcquireTradeEvent + + +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 deac9d6389493213e2b0cc8e2b6ae0c9f055c011..5ea56c6048a356d84472ef0e744af41fe063ccc7 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java +@@ -273,7 +273,11 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa + Bukkit.getPluginManager().callEvent(event); + } + if (!event.isCancelled()) { +- recipeList.add(CraftMerchantRecipe.fromBukkit(event.getRecipe()).toMinecraft()); ++ // Paper start - Fix crash from invalid ingredient list ++ final CraftMerchantRecipe craftMerchantRecipe = CraftMerchantRecipe.fromBukkit(event.getRecipe()); ++ if (craftMerchantRecipe.getIngredients().isEmpty()) return; ++ recipeList.add(craftMerchantRecipe.toMinecraft()); ++ // Paper end - Fix crash from invalid ingredient list + } + // CraftBukkit end + ++j; diff --git a/patches/server/0441-Add-TargetHitEvent.patch b/patches/server/0441-Add-TargetHitEvent.patch new file mode 100644 index 0000000000..816c525fd2 --- /dev/null +++ b/patches/server/0441-Add-TargetHitEvent.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Wed, 25 Nov 2020 23:20:44 -0800 +Subject: [PATCH] Add TargetHitEvent + + +diff --git a/src/main/java/net/minecraft/world/level/block/TargetBlock.java b/src/main/java/net/minecraft/world/level/block/TargetBlock.java +index 549ca8e9b265635bd3d5863682fe240f3f9f3f58..ee4eb863b6c02f2bcbb03ca413fc98811d409ac5 100644 +--- a/src/main/java/net/minecraft/world/level/block/TargetBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/TargetBlock.java +@@ -42,6 +42,10 @@ public class TargetBlock extends Block { + @Override + protected void onProjectileHit(Level world, BlockState state, BlockHitResult hit, Projectile projectile) { + int i = updateRedstoneOutput(world, state, hit, projectile); ++ // Paper start - Add TargetHitEvent ++ } ++ private static void awardTargetHitCriteria(Projectile projectile, BlockHitResult hit, int i) { ++ // Paper end - Add TargetHitEvent + if (projectile.getOwner() instanceof ServerPlayer serverPlayer) { + serverPlayer.awardStat(Stats.TARGET_HIT); + CriteriaTriggers.TARGET_BLOCK_HIT.trigger(serverPlayer, projectile, hit.getLocation(), i); +@@ -51,10 +55,31 @@ public class TargetBlock extends Block { + private static int updateRedstoneOutput(LevelAccessor world, BlockState state, BlockHitResult hitResult, Entity entity) { + int i = getRedstoneStrength(hitResult, hitResult.getLocation()); + int j = entity instanceof AbstractArrow ? 20 : 8; ++ // Paper start - Add TargetHitEvent ++ boolean shouldAward = false; ++ if (entity instanceof Projectile) { ++ final Projectile projectile = (Projectile) entity; ++ final org.bukkit.craftbukkit.block.CraftBlock craftBlock = org.bukkit.craftbukkit.block.CraftBlock.at(world, hitResult.getBlockPos()); ++ final org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(hitResult.getDirection()); ++ final io.papermc.paper.event.block.TargetHitEvent targetHitEvent = new io.papermc.paper.event.block.TargetHitEvent((org.bukkit.entity.Projectile) projectile.getBukkitEntity(), craftBlock, blockFace, i); ++ if (targetHitEvent.callEvent()) { ++ i = targetHitEvent.getSignalStrength(); ++ shouldAward = true; ++ } else { ++ return i; ++ } ++ } ++ // Paper end - Add TargetHitEvent + if (!world.getBlockTicks().hasScheduledTick(hitResult.getBlockPos(), state.getBlock())) { + setOutputPower(world, state, i, hitResult.getBlockPos(), j); + } + ++ // Paper start - Award Hit Criteria after Block Update ++ if (shouldAward) { ++ awardTargetHitCriteria((Projectile) entity, hitResult, i); ++ } ++ // Paper end - Award Hit Criteria after Block Update ++ + return i; + } + diff --git a/patches/server/0441-Fix-crash-from-invalid-ingredient-lists-in-VillagerA.patch b/patches/server/0441-Fix-crash-from-invalid-ingredient-lists-in-VillagerA.patch deleted file mode 100644 index 3122449eed..0000000000 --- a/patches/server/0441-Fix-crash-from-invalid-ingredient-lists-in-VillagerA.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sun, 27 Dec 2020 11:31:06 +0000 -Subject: [PATCH] Fix crash from invalid ingredient lists in - VillagerAcquireTradeEvent - - -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 deac9d6389493213e2b0cc8e2b6ae0c9f055c011..5ea56c6048a356d84472ef0e744af41fe063ccc7 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -@@ -273,7 +273,11 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa - Bukkit.getPluginManager().callEvent(event); - } - if (!event.isCancelled()) { -- recipeList.add(CraftMerchantRecipe.fromBukkit(event.getRecipe()).toMinecraft()); -+ // Paper start - Fix crash from invalid ingredient list -+ final CraftMerchantRecipe craftMerchantRecipe = CraftMerchantRecipe.fromBukkit(event.getRecipe()); -+ if (craftMerchantRecipe.getIngredients().isEmpty()) return; -+ recipeList.add(craftMerchantRecipe.toMinecraft()); -+ // Paper end - Fix crash from invalid ingredient list - } - // CraftBukkit end - ++j; diff --git a/patches/server/0442-Add-TargetHitEvent.patch b/patches/server/0442-Add-TargetHitEvent.patch deleted file mode 100644 index 816c525fd2..0000000000 --- a/patches/server/0442-Add-TargetHitEvent.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Wed, 25 Nov 2020 23:20:44 -0800 -Subject: [PATCH] Add TargetHitEvent - - -diff --git a/src/main/java/net/minecraft/world/level/block/TargetBlock.java b/src/main/java/net/minecraft/world/level/block/TargetBlock.java -index 549ca8e9b265635bd3d5863682fe240f3f9f3f58..ee4eb863b6c02f2bcbb03ca413fc98811d409ac5 100644 ---- a/src/main/java/net/minecraft/world/level/block/TargetBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TargetBlock.java -@@ -42,6 +42,10 @@ public class TargetBlock extends Block { - @Override - protected void onProjectileHit(Level world, BlockState state, BlockHitResult hit, Projectile projectile) { - int i = updateRedstoneOutput(world, state, hit, projectile); -+ // Paper start - Add TargetHitEvent -+ } -+ private static void awardTargetHitCriteria(Projectile projectile, BlockHitResult hit, int i) { -+ // Paper end - Add TargetHitEvent - if (projectile.getOwner() instanceof ServerPlayer serverPlayer) { - serverPlayer.awardStat(Stats.TARGET_HIT); - CriteriaTriggers.TARGET_BLOCK_HIT.trigger(serverPlayer, projectile, hit.getLocation(), i); -@@ -51,10 +55,31 @@ public class TargetBlock extends Block { - private static int updateRedstoneOutput(LevelAccessor world, BlockState state, BlockHitResult hitResult, Entity entity) { - int i = getRedstoneStrength(hitResult, hitResult.getLocation()); - int j = entity instanceof AbstractArrow ? 20 : 8; -+ // Paper start - Add TargetHitEvent -+ boolean shouldAward = false; -+ if (entity instanceof Projectile) { -+ final Projectile projectile = (Projectile) entity; -+ final org.bukkit.craftbukkit.block.CraftBlock craftBlock = org.bukkit.craftbukkit.block.CraftBlock.at(world, hitResult.getBlockPos()); -+ final org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(hitResult.getDirection()); -+ final io.papermc.paper.event.block.TargetHitEvent targetHitEvent = new io.papermc.paper.event.block.TargetHitEvent((org.bukkit.entity.Projectile) projectile.getBukkitEntity(), craftBlock, blockFace, i); -+ if (targetHitEvent.callEvent()) { -+ i = targetHitEvent.getSignalStrength(); -+ shouldAward = true; -+ } else { -+ return i; -+ } -+ } -+ // Paper end - Add TargetHitEvent - if (!world.getBlockTicks().hasScheduledTick(hitResult.getBlockPos(), state.getBlock())) { - setOutputPower(world, state, i, hitResult.getBlockPos(), j); - } - -+ // Paper start - Award Hit Criteria after Block Update -+ if (shouldAward) { -+ awardTargetHitCriteria((Projectile) entity, hitResult, i); -+ } -+ // Paper end - Award Hit Criteria after Block Update -+ - return i; - } - diff --git a/patches/server/0442-MC-4-Fix-item-position-desync.patch b/patches/server/0442-MC-4-Fix-item-position-desync.patch new file mode 100644 index 0000000000..0451493f65 --- /dev/null +++ b/patches/server/0442-MC-4-Fix-item-position-desync.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 8 Dec 2020 20:24:52 -0600 +Subject: [PATCH] MC-4: Fix item position desync + +This fixes item position desync (MC-4) by running the item coordinates +through the encode/decode methods of the packet that causes the precision +loss, which forces the server to lose the same precision as the client +keeping them in sync. + +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 488ebd443903af812913437f1ade3002093f2470..a043ac10834562d357ef0b5aded2e916e2a0d056 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java ++++ b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java +@@ -9,12 +9,12 @@ public class VecDeltaCodec { + + @VisibleForTesting + static long encode(double value) { +- return Math.round(value * 4096.0); ++ return Math.round(value * 4096.0); // Paper - Fix MC-4; diff on change + } + + @VisibleForTesting + static double decode(long value) { +- return (double)value / 4096.0; ++ return value / 4096.0; // Paper - Fix MC-4; diff on change + } + + public Vec3 decode(long x, long y, long z) { +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 20e6b199758130d5c758c79488031c40849cc51d..0d99d310746cc584b2d89d0c1b7083049f4d1593 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -4505,6 +4505,16 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return; + } + // Paper end - Block invalid positions and bounding box ++ // Paper start - Fix MC-4 ++ if (this instanceof ItemEntity) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.fixEntityPositionDesync) { ++ // encode/decode from ClientboundMoveEntityPacket ++ x = Mth.lfloor(x * 4096.0) * (1 / 4096.0); ++ y = Mth.lfloor(y * 4096.0) * (1 / 4096.0); ++ z = Mth.lfloor(z * 4096.0) * (1 / 4096.0); ++ } ++ } ++ // Paper end - Fix MC-4 + if (this.position.x != x || this.position.y != y || this.position.z != z) { + this.position = new Vec3(x, y, z); + int i = Mth.floor(x); diff --git a/patches/server/0443-Additional-Block-Material-API.patch b/patches/server/0443-Additional-Block-Material-API.patch new file mode 100644 index 0000000000..19f5b4b7ef --- /dev/null +++ b/patches/server/0443-Additional-Block-Material-API.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 30 Dec 2020 19:43:01 -0500 +Subject: [PATCH] Additional Block Material API + +Faster version for isSolid() that utilizes NMS's state for isSolid instead of the slower +process to do this in the Bukkit API + +Adds API for buildable, replaceable, burnable too. + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 5f4dcf6d86db66186dc31075bdb739f5dbae6480..1595e877b02b447b36f5c316ae70d4023b78a862 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -440,6 +440,25 @@ public class CraftBlock implements Block { + return this.getNMS().liquid(); + } + ++ // Paper start ++ @Override ++ public boolean isBuildable() { ++ return this.getNMS().isSolid(); // This is in fact isSolid, despite the fact that isSolid below returns blocksMotion ++ } ++ @Override ++ public boolean isBurnable() { ++ return this.getNMS().ignitedByLava(); ++ } ++ @Override ++ public boolean isReplaceable() { ++ return this.getNMS().canBeReplaced(); ++ } ++ @Override ++ public boolean isSolid() { ++ return this.getNMS().blocksMotion(); ++ } ++ // Paper end ++ + @Override + public PistonMoveReaction getPistonMoveReaction() { + return PistonMoveReaction.getById(this.getNMS().getPistonPushReaction().ordinal()); diff --git a/patches/server/0443-MC-4-Fix-item-position-desync.patch b/patches/server/0443-MC-4-Fix-item-position-desync.patch deleted file mode 100644 index f3354a6790..0000000000 --- a/patches/server/0443-MC-4-Fix-item-position-desync.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Tue, 8 Dec 2020 20:24:52 -0600 -Subject: [PATCH] MC-4: Fix item position desync - -This fixes item position desync (MC-4) by running the item coordinates -through the encode/decode methods of the packet that causes the precision -loss, which forces the server to lose the same precision as the client -keeping them in sync. - -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 488ebd443903af812913437f1ade3002093f2470..a043ac10834562d357ef0b5aded2e916e2a0d056 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java -+++ b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java -@@ -9,12 +9,12 @@ public class VecDeltaCodec { - - @VisibleForTesting - static long encode(double value) { -- return Math.round(value * 4096.0); -+ return Math.round(value * 4096.0); // Paper - Fix MC-4; diff on change - } - - @VisibleForTesting - static double decode(long value) { -- return (double)value / 4096.0; -+ return value / 4096.0; // Paper - Fix MC-4; diff on change - } - - public Vec3 decode(long x, long y, long z) { -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index fc40880fadb20f7c274c94b1e6a2fa6d0118e672..64ea966438b0ec9d029b628543177b0faa2c259d 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4505,6 +4505,16 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return; - } - // Paper end - Block invalid positions and bounding box -+ // Paper start - Fix MC-4 -+ if (this instanceof ItemEntity) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.fixEntityPositionDesync) { -+ // encode/decode from ClientboundMoveEntityPacket -+ x = Mth.lfloor(x * 4096.0) * (1 / 4096.0); -+ y = Mth.lfloor(y * 4096.0) * (1 / 4096.0); -+ z = Mth.lfloor(z * 4096.0) * (1 / 4096.0); -+ } -+ } -+ // Paper end - Fix MC-4 - if (this.position.x != x || this.position.y != y || this.position.z != z) { - this.position = new Vec3(x, y, z); - int i = Mth.floor(x); diff --git a/patches/server/0444-API-to-get-Material-from-Boats-and-Minecarts.patch b/patches/server/0444-API-to-get-Material-from-Boats-and-Minecarts.patch new file mode 100644 index 0000000000..25467e469e --- /dev/null +++ b/patches/server/0444-API-to-get-Material-from-Boats-and-Minecarts.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Madeline Miller +Date: Thu, 31 Dec 2020 12:48:19 +1000 +Subject: [PATCH] API to get Material from Boats and Minecarts + +== AT == +public net.minecraft.world.entity.vehicle.AbstractBoat getDropItem()Lnet/minecraft/world/item/Item; + +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 fb9f0a62201dfeccd0eec9bb399f9edc6a01f1f0..d01a588aea379c962dd63f1428f92cf2442f4d45 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java +@@ -717,4 +717,5 @@ public abstract class AbstractMinecart extends VehicleEntity { + this.derailedZ = derailed.getZ(); + } + // CraftBukkit end ++ public net.minecraft.world.item.Item publicGetDropItem() { return getDropItem(); } // Paper - api to get boat and minecart material - expose public drop item + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java +index c101d01b55472efc9fc2829b8c17db5377ed57ff..5d51a49228eaee94f91cd04843e27c7918ca8796 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java +@@ -78,6 +78,13 @@ public abstract class CraftBoat extends CraftVehicle implements Boat { + this.getHandle().landBoats = workOnLand; + } + ++ // Paper start ++ @Override ++ public org.bukkit.Material getBoatMaterial() { ++ return org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(this.getHandle().getDropItem()); ++ } ++ // Paper end ++ + @Override + public Status getStatus() { + return CraftBoat.boatStatusFromNms(this.getHandle().status); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java +index c4db7c00c66e064993b8b2158f226d063eea798c..e02ecbdc158311bdc7e4d13307de6e2a2cf54235 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java +@@ -4,6 +4,7 @@ import net.minecraft.server.level.ServerLevel; + import net.minecraft.world.entity.vehicle.AbstractMinecart; + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.BlockState; ++import org.bukkit.Material; // Paper + import org.bukkit.block.data.BlockData; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.craftbukkit.block.data.CraftBlockData; +@@ -69,6 +70,13 @@ public abstract class CraftMinecart extends CraftVehicle implements Minecart { + this.getHandle().setDerailedVelocityMod(derailed); + } + ++ // Paper start ++ @Override ++ public Material getMinecartMaterial() { ++ return CraftMagicNumbers.getMaterial(this.getHandle().publicGetDropItem()); ++ } ++ // Paper end ++ + @Override + public AbstractMinecart getHandle() { + return (AbstractMinecart) this.entity; diff --git a/patches/server/0444-Additional-Block-Material-API.patch b/patches/server/0444-Additional-Block-Material-API.patch deleted file mode 100644 index 19f5b4b7ef..0000000000 --- a/patches/server/0444-Additional-Block-Material-API.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 30 Dec 2020 19:43:01 -0500 -Subject: [PATCH] Additional Block Material API - -Faster version for isSolid() that utilizes NMS's state for isSolid instead of the slower -process to do this in the Bukkit API - -Adds API for buildable, replaceable, burnable too. - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 5f4dcf6d86db66186dc31075bdb739f5dbae6480..1595e877b02b447b36f5c316ae70d4023b78a862 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -440,6 +440,25 @@ public class CraftBlock implements Block { - return this.getNMS().liquid(); - } - -+ // Paper start -+ @Override -+ public boolean isBuildable() { -+ return this.getNMS().isSolid(); // This is in fact isSolid, despite the fact that isSolid below returns blocksMotion -+ } -+ @Override -+ public boolean isBurnable() { -+ return this.getNMS().ignitedByLava(); -+ } -+ @Override -+ public boolean isReplaceable() { -+ return this.getNMS().canBeReplaced(); -+ } -+ @Override -+ public boolean isSolid() { -+ return this.getNMS().blocksMotion(); -+ } -+ // Paper end -+ - @Override - public PistonMoveReaction getPistonMoveReaction() { - return PistonMoveReaction.getById(this.getNMS().getPistonPushReaction().ordinal()); diff --git a/patches/server/0445-API-to-get-Material-from-Boats-and-Minecarts.patch b/patches/server/0445-API-to-get-Material-from-Boats-and-Minecarts.patch deleted file mode 100644 index 25467e469e..0000000000 --- a/patches/server/0445-API-to-get-Material-from-Boats-and-Minecarts.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Madeline Miller -Date: Thu, 31 Dec 2020 12:48:19 +1000 -Subject: [PATCH] API to get Material from Boats and Minecarts - -== AT == -public net.minecraft.world.entity.vehicle.AbstractBoat getDropItem()Lnet/minecraft/world/item/Item; - -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 fb9f0a62201dfeccd0eec9bb399f9edc6a01f1f0..d01a588aea379c962dd63f1428f92cf2442f4d45 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -@@ -717,4 +717,5 @@ public abstract class AbstractMinecart extends VehicleEntity { - this.derailedZ = derailed.getZ(); - } - // CraftBukkit end -+ public net.minecraft.world.item.Item publicGetDropItem() { return getDropItem(); } // Paper - api to get boat and minecart material - expose public drop item - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java -index c101d01b55472efc9fc2829b8c17db5377ed57ff..5d51a49228eaee94f91cd04843e27c7918ca8796 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java -@@ -78,6 +78,13 @@ public abstract class CraftBoat extends CraftVehicle implements Boat { - this.getHandle().landBoats = workOnLand; - } - -+ // Paper start -+ @Override -+ public org.bukkit.Material getBoatMaterial() { -+ return org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(this.getHandle().getDropItem()); -+ } -+ // Paper end -+ - @Override - public Status getStatus() { - return CraftBoat.boatStatusFromNms(this.getHandle().status); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java -index c4db7c00c66e064993b8b2158f226d063eea798c..e02ecbdc158311bdc7e4d13307de6e2a2cf54235 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java -@@ -4,6 +4,7 @@ import net.minecraft.server.level.ServerLevel; - import net.minecraft.world.entity.vehicle.AbstractMinecart; - import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.state.BlockState; -+import org.bukkit.Material; // Paper - import org.bukkit.block.data.BlockData; - import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.craftbukkit.block.data.CraftBlockData; -@@ -69,6 +70,13 @@ public abstract class CraftMinecart extends CraftVehicle implements Minecart { - this.getHandle().setDerailedVelocityMod(derailed); - } - -+ // Paper start -+ @Override -+ public Material getMinecartMaterial() { -+ return CraftMagicNumbers.getMaterial(this.getHandle().publicGetDropItem()); -+ } -+ // Paper end -+ - @Override - public AbstractMinecart getHandle() { - return (AbstractMinecart) this.entity; diff --git a/patches/server/0445-Allow-disabling-mob-spawner-spawn-egg-transformation.patch b/patches/server/0445-Allow-disabling-mob-spawner-spawn-egg-transformation.patch new file mode 100644 index 0000000000..140d605ba0 --- /dev/null +++ b/patches/server/0445-Allow-disabling-mob-spawner-spawn-egg-transformation.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BrodyBeckwith +Date: Fri, 9 Oct 2020 20:30:12 -0400 +Subject: [PATCH] Allow disabling mob spawner spawn egg transformation + + +diff --git a/src/main/java/net/minecraft/world/item/SpawnEggItem.java b/src/main/java/net/minecraft/world/item/SpawnEggItem.java +index ecc3193b4276a083461780eddab9f7b1c34175a8..cc7e9b87e919b4ef8cf77cd780c890fd9a9cfa50 100644 +--- a/src/main/java/net/minecraft/world/item/SpawnEggItem.java ++++ b/src/main/java/net/minecraft/world/item/SpawnEggItem.java +@@ -63,6 +63,8 @@ public class SpawnEggItem extends Item { + EntityType entitytypes; + + if (tileentity instanceof Spawner) { ++ if (world.paperConfig().entities.spawning.disableMobSpawnerSpawnEggTransformation) return InteractionResult.FAIL; // Paper - Allow disabling mob spawner spawn egg transformation ++ + Spawner spawner = (Spawner) tileentity; + + entitytypes = this.getType(world.registryAccess(), itemstack); diff --git a/patches/server/0446-Allow-disabling-mob-spawner-spawn-egg-transformation.patch b/patches/server/0446-Allow-disabling-mob-spawner-spawn-egg-transformation.patch deleted file mode 100644 index 140d605ba0..0000000000 --- a/patches/server/0446-Allow-disabling-mob-spawner-spawn-egg-transformation.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BrodyBeckwith -Date: Fri, 9 Oct 2020 20:30:12 -0400 -Subject: [PATCH] Allow disabling mob spawner spawn egg transformation - - -diff --git a/src/main/java/net/minecraft/world/item/SpawnEggItem.java b/src/main/java/net/minecraft/world/item/SpawnEggItem.java -index ecc3193b4276a083461780eddab9f7b1c34175a8..cc7e9b87e919b4ef8cf77cd780c890fd9a9cfa50 100644 ---- a/src/main/java/net/minecraft/world/item/SpawnEggItem.java -+++ b/src/main/java/net/minecraft/world/item/SpawnEggItem.java -@@ -63,6 +63,8 @@ public class SpawnEggItem extends Item { - EntityType entitytypes; - - if (tileentity instanceof Spawner) { -+ if (world.paperConfig().entities.spawning.disableMobSpawnerSpawnEggTransformation) return InteractionResult.FAIL; // Paper - Allow disabling mob spawner spawn egg transformation -+ - Spawner spawner = (Spawner) tileentity; - - entitytypes = this.getType(world.registryAccess(), itemstack); diff --git a/patches/server/0446-Fix-Not-a-string-Map-Conversion-spam.patch b/patches/server/0446-Fix-Not-a-string-Map-Conversion-spam.patch new file mode 100644 index 0000000000..8952de7633 --- /dev/null +++ b/patches/server/0446-Fix-Not-a-string-Map-Conversion-spam.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 8 Oct 2020 00:00:25 -0400 +Subject: [PATCH] Fix "Not a string" Map Conversion spam + +The maps did convert successfully, but had noisy logs due to Spigot +implementing this logic incorrectly. + +This stops the spam by converting the old format to new before +requesting the world. + +Track spigot issue to see when fixed: https://hub.spigotmc.org/jira/browse/SPIGOT-6181 + +diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +index c21ae4975206398e7d20b37a749b830b9219c746..a89f0b652c515efbc24ffc9af47fa65082946e54 100644 +--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java ++++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +@@ -123,7 +123,26 @@ public class MapItemSavedData extends SavedData { + } + + public static MapItemSavedData load(CompoundTag nbt, HolderLookup.Provider registries) { +- DataResult> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbt.get("dimension"))); // CraftBukkit - decompile error ++ // Paper start - fix "Not a string" spam ++ Tag dimension = nbt.get("dimension"); ++ if (dimension instanceof final net.minecraft.nbt.NumericTag numericTag && numericTag.getAsInt() >= CraftWorld.CUSTOM_DIMENSION_OFFSET) { ++ long least = nbt.getLong("UUIDLeast"); ++ long most = nbt.getLong("UUIDMost"); ++ ++ if (least != 0L && most != 0L) { ++ UUID uuid = new UUID(most, least); ++ CraftWorld world = (CraftWorld) Bukkit.getWorld(uuid); ++ if (world != null) { ++ dimension = net.minecraft.nbt.StringTag.valueOf("minecraft:" + world.getName().toLowerCase(java.util.Locale.ENGLISH)); ++ } else { ++ dimension = net.minecraft.nbt.StringTag.valueOf("bukkit:_invalidworld_"); ++ } ++ } else { ++ dimension = net.minecraft.nbt.StringTag.valueOf("bukkit:_invalidworld_"); ++ } ++ } ++ DataResult> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, dimension)); // CraftBukkit - decompile error ++ // Paper end - fix "Not a string" spam + Logger logger = MapItemSavedData.LOGGER; + + Objects.requireNonNull(logger); diff --git a/patches/server/0447-Add-PlayerFlowerPotManipulateEvent.patch b/patches/server/0447-Add-PlayerFlowerPotManipulateEvent.patch new file mode 100644 index 0000000000..8b8fb61ee2 --- /dev/null +++ b/patches/server/0447-Add-PlayerFlowerPotManipulateEvent.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MisterVector +Date: Tue, 13 Aug 2019 19:45:06 -0700 +Subject: [PATCH] Add PlayerFlowerPotManipulateEvent + + +diff --git a/src/main/java/net/minecraft/world/level/block/FlowerPotBlock.java b/src/main/java/net/minecraft/world/level/block/FlowerPotBlock.java +index 4c7723b9f369391ab253c4a60510e318fb7cfce3..f45a8741e6707f033b0205eee03c59aa889565e1 100644 +--- a/src/main/java/net/minecraft/world/level/block/FlowerPotBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/FlowerPotBlock.java +@@ -63,6 +63,18 @@ public class FlowerPotBlock extends Block { + } else if (!this.isEmpty()) { + return InteractionResult.CONSUME; + } else { ++ // Paper start - Add PlayerFlowerPotManipulateEvent ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos); ++ org.bukkit.inventory.ItemStack placedStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(stack); ++ ++ io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, placedStack, true); ++ if (!event.callEvent()) { ++ // Update client ++ player.containerMenu.sendAllDataToRemote(); ++ ++ return InteractionResult.CONSUME; ++ } ++ // Paper end - Add PlayerFlowerPotManipulateEvent + world.setBlock(pos, blockState, 3); + world.gameEvent(player, GameEvent.BLOCK_CHANGE, pos); + player.awardStat(Stats.POT_FLOWER); +@@ -77,6 +89,18 @@ public class FlowerPotBlock extends Block { + return InteractionResult.CONSUME; + } else { + ItemStack itemStack = new ItemStack(this.potted); ++ // Paper start - Add PlayerFlowerPotManipulateEvent ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos); ++ org.bukkit.inventory.ItemStack pottedStack = new org.bukkit.inventory.ItemStack(org.bukkit.craftbukkit.block.CraftBlockType.minecraftToBukkit(this.potted)); ++ ++ io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, pottedStack, false); ++ if (!event.callEvent()) { ++ // Update client ++ player.containerMenu.sendAllDataToRemote(); ++ ++ return InteractionResult.PASS; ++ } ++ // Paper end - Add PlayerFlowerPotManipulateEvent + if (!player.addItem(itemStack)) { + player.drop(itemStack, false); + } diff --git a/patches/server/0447-Fix-Not-a-string-Map-Conversion-spam.patch b/patches/server/0447-Fix-Not-a-string-Map-Conversion-spam.patch deleted file mode 100644 index 8952de7633..0000000000 --- a/patches/server/0447-Fix-Not-a-string-Map-Conversion-spam.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 8 Oct 2020 00:00:25 -0400 -Subject: [PATCH] Fix "Not a string" Map Conversion spam - -The maps did convert successfully, but had noisy logs due to Spigot -implementing this logic incorrectly. - -This stops the spam by converting the old format to new before -requesting the world. - -Track spigot issue to see when fixed: https://hub.spigotmc.org/jira/browse/SPIGOT-6181 - -diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -index c21ae4975206398e7d20b37a749b830b9219c746..a89f0b652c515efbc24ffc9af47fa65082946e54 100644 ---- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -123,7 +123,26 @@ public class MapItemSavedData extends SavedData { - } - - public static MapItemSavedData load(CompoundTag nbt, HolderLookup.Provider registries) { -- DataResult> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbt.get("dimension"))); // CraftBukkit - decompile error -+ // Paper start - fix "Not a string" spam -+ Tag dimension = nbt.get("dimension"); -+ if (dimension instanceof final net.minecraft.nbt.NumericTag numericTag && numericTag.getAsInt() >= CraftWorld.CUSTOM_DIMENSION_OFFSET) { -+ long least = nbt.getLong("UUIDLeast"); -+ long most = nbt.getLong("UUIDMost"); -+ -+ if (least != 0L && most != 0L) { -+ UUID uuid = new UUID(most, least); -+ CraftWorld world = (CraftWorld) Bukkit.getWorld(uuid); -+ if (world != null) { -+ dimension = net.minecraft.nbt.StringTag.valueOf("minecraft:" + world.getName().toLowerCase(java.util.Locale.ENGLISH)); -+ } else { -+ dimension = net.minecraft.nbt.StringTag.valueOf("bukkit:_invalidworld_"); -+ } -+ } else { -+ dimension = net.minecraft.nbt.StringTag.valueOf("bukkit:_invalidworld_"); -+ } -+ } -+ DataResult> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, dimension)); // CraftBukkit - decompile error -+ // Paper end - fix "Not a string" spam - Logger logger = MapItemSavedData.LOGGER; - - Objects.requireNonNull(logger); diff --git a/patches/server/0448-Add-PlayerFlowerPotManipulateEvent.patch b/patches/server/0448-Add-PlayerFlowerPotManipulateEvent.patch deleted file mode 100644 index 8b8fb61ee2..0000000000 --- a/patches/server/0448-Add-PlayerFlowerPotManipulateEvent.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MisterVector -Date: Tue, 13 Aug 2019 19:45:06 -0700 -Subject: [PATCH] Add PlayerFlowerPotManipulateEvent - - -diff --git a/src/main/java/net/minecraft/world/level/block/FlowerPotBlock.java b/src/main/java/net/minecraft/world/level/block/FlowerPotBlock.java -index 4c7723b9f369391ab253c4a60510e318fb7cfce3..f45a8741e6707f033b0205eee03c59aa889565e1 100644 ---- a/src/main/java/net/minecraft/world/level/block/FlowerPotBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FlowerPotBlock.java -@@ -63,6 +63,18 @@ public class FlowerPotBlock extends Block { - } else if (!this.isEmpty()) { - return InteractionResult.CONSUME; - } else { -+ // Paper start - Add PlayerFlowerPotManipulateEvent -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos); -+ org.bukkit.inventory.ItemStack placedStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(stack); -+ -+ io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, placedStack, true); -+ if (!event.callEvent()) { -+ // Update client -+ player.containerMenu.sendAllDataToRemote(); -+ -+ return InteractionResult.CONSUME; -+ } -+ // Paper end - Add PlayerFlowerPotManipulateEvent - world.setBlock(pos, blockState, 3); - world.gameEvent(player, GameEvent.BLOCK_CHANGE, pos); - player.awardStat(Stats.POT_FLOWER); -@@ -77,6 +89,18 @@ public class FlowerPotBlock extends Block { - return InteractionResult.CONSUME; - } else { - ItemStack itemStack = new ItemStack(this.potted); -+ // Paper start - Add PlayerFlowerPotManipulateEvent -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos); -+ org.bukkit.inventory.ItemStack pottedStack = new org.bukkit.inventory.ItemStack(org.bukkit.craftbukkit.block.CraftBlockType.minecraftToBukkit(this.potted)); -+ -+ io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, pottedStack, false); -+ if (!event.callEvent()) { -+ // Update client -+ player.containerMenu.sendAllDataToRemote(); -+ -+ return InteractionResult.PASS; -+ } -+ // Paper end - Add PlayerFlowerPotManipulateEvent - if (!player.addItem(itemStack)) { - player.drop(itemStack, false); - } diff --git a/patches/server/0448-Fix-interact-event-not-being-called-sometimes.patch b/patches/server/0448-Fix-interact-event-not-being-called-sometimes.patch new file mode 100644 index 0000000000..d8a7435cf0 --- /dev/null +++ b/patches/server/0448-Fix-interact-event-not-being-called-sometimes.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TheMolkaPL +Date: Sun, 21 Jun 2020 17:21:46 +0200 +Subject: [PATCH] Fix interact event not being called sometimes + +* Call PlayerInteractEvent when left-clicking on a block in adventure + mode. +* Call PlayerInteractEvent when left-clicking an Entity that is out of + range in adventure/survival (entity reach is 3.0). + +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 04de96af5415c3115703f5ab42e9fa3aa2ccee60..76b6c3fca13590f057dc4767d27fef4192974147 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1842,7 +1842,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } else if (enuminteractionresult instanceof InteractionResult.Success) { + InteractionResult.Success enuminteractionresult_d = (InteractionResult.Success) enuminteractionresult; + +- if (enuminteractionresult_d.swingSource() == InteractionResult.SwingSource.SERVER) { ++ if (enuminteractionresult_d.swingSource() == InteractionResult.SwingSource.SERVER && !this.player.gameMode.interactResult) { // Paper - Call interact event + this.player.swing(enumhand, true); + } + } +@@ -2466,13 +2466,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 +- org.bukkit.util.RayTraceResult result = this.player.level().getWorld().rayTrace(origin, origin.getDirection(), d3, org.bukkit.FluidCollisionMode.NEVER, false, 0.1, entity -> { ++ org.bukkit.util.RayTraceResult result = this.player.level().getWorld().rayTrace(origin, origin.getDirection(), d3, org.bukkit.FluidCollisionMode.NEVER, false, 0.0, entity -> { // Paper - Call interact event; change raySize from 0.1 to 0.0 + Entity handle = ((CraftEntity) entity).getHandle(); + return entity != this.player.getBukkitEntity() && this.player.getBukkitEntity().canSee(entity) && !handle.isSpectator() && handle.isPickable() && !handle.isPassengerOfSameVehicle(this.player); + }); + if (result == null) { + CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_AIR, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); +- } ++ } else { // Paper start - Call interact event ++ GameType gameType = this.player.gameMode.getGameModeForPlayer(); ++ if (gameType == GameType.ADVENTURE && result.getHitBlock() != null) { ++ CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, ((org.bukkit.craftbukkit.block.CraftBlock) result.getHitBlock()).getPosition(), org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(result.getHitBlockFace()), this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); ++ } else if (gameType != GameType.CREATIVE && result.getHitEntity() != null && origin.toVector().distanceSquared(result.getHitPosition()) > this.player.entityInteractionRange() * this.player.entityInteractionRange()) { ++ CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_AIR, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); ++ } ++ } // Paper end - Call interact event + + // Arm swing animation + PlayerAnimationEvent event = new PlayerAnimationEvent(this.getCraftPlayer(), (packet.getHand() == InteractionHand.MAIN_HAND) ? PlayerAnimationType.ARM_SWING : PlayerAnimationType.OFF_ARM_SWING); diff --git a/patches/server/0449-Fix-interact-event-not-being-called-sometimes.patch b/patches/server/0449-Fix-interact-event-not-being-called-sometimes.patch deleted file mode 100644 index d8a7435cf0..0000000000 --- a/patches/server/0449-Fix-interact-event-not-being-called-sometimes.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TheMolkaPL -Date: Sun, 21 Jun 2020 17:21:46 +0200 -Subject: [PATCH] Fix interact event not being called sometimes - -* Call PlayerInteractEvent when left-clicking on a block in adventure - mode. -* Call PlayerInteractEvent when left-clicking an Entity that is out of - range in adventure/survival (entity reach is 3.0). - -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 04de96af5415c3115703f5ab42e9fa3aa2ccee60..76b6c3fca13590f057dc4767d27fef4192974147 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1842,7 +1842,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } else if (enuminteractionresult instanceof InteractionResult.Success) { - InteractionResult.Success enuminteractionresult_d = (InteractionResult.Success) enuminteractionresult; - -- if (enuminteractionresult_d.swingSource() == InteractionResult.SwingSource.SERVER) { -+ if (enuminteractionresult_d.swingSource() == InteractionResult.SwingSource.SERVER && !this.player.gameMode.interactResult) { // Paper - Call interact event - this.player.swing(enumhand, true); - } - } -@@ -2466,13 +2466,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 -- org.bukkit.util.RayTraceResult result = this.player.level().getWorld().rayTrace(origin, origin.getDirection(), d3, org.bukkit.FluidCollisionMode.NEVER, false, 0.1, entity -> { -+ org.bukkit.util.RayTraceResult result = this.player.level().getWorld().rayTrace(origin, origin.getDirection(), d3, org.bukkit.FluidCollisionMode.NEVER, false, 0.0, entity -> { // Paper - Call interact event; change raySize from 0.1 to 0.0 - Entity handle = ((CraftEntity) entity).getHandle(); - return entity != this.player.getBukkitEntity() && this.player.getBukkitEntity().canSee(entity) && !handle.isSpectator() && handle.isPickable() && !handle.isPassengerOfSameVehicle(this.player); - }); - if (result == null) { - CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_AIR, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); -- } -+ } else { // Paper start - Call interact event -+ GameType gameType = this.player.gameMode.getGameModeForPlayer(); -+ if (gameType == GameType.ADVENTURE && result.getHitBlock() != null) { -+ CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, ((org.bukkit.craftbukkit.block.CraftBlock) result.getHitBlock()).getPosition(), org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(result.getHitBlockFace()), this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); -+ } else if (gameType != GameType.CREATIVE && result.getHitEntity() != null && origin.toVector().distanceSquared(result.getHitPosition()) > this.player.entityInteractionRange() * this.player.entityInteractionRange()) { -+ CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_AIR, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND); -+ } -+ } // Paper end - Call interact event - - // Arm swing animation - PlayerAnimationEvent event = new PlayerAnimationEvent(this.getCraftPlayer(), (packet.getHand() == InteractionHand.MAIN_HAND) ? PlayerAnimationType.ARM_SWING : PlayerAnimationType.OFF_ARM_SWING); diff --git a/patches/server/0449-Zombie-API-breaking-doors.patch b/patches/server/0449-Zombie-API-breaking-doors.patch new file mode 100644 index 0000000000..b0741f110f --- /dev/null +++ b/patches/server/0449-Zombie-API-breaking-doors.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 18 Nov 2020 11:32:46 -0800 +Subject: [PATCH] Zombie API - breaking doors + +== AT == +public net.minecraft.world.entity.monster.Zombie supportsBreakDoorGoal()Z + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java +index 4412c913123f7521f449c98b60378e8d3b1671ce..dfc2b40e20069705f92d86a6898e3e8348bf4dcd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java +@@ -122,6 +122,11 @@ public class CraftZombie extends CraftMonster implements Zombie { + public void setShouldBurnInDay(boolean shouldBurnInDay) { + getHandle().setShouldBurnInDay(shouldBurnInDay); + } ++ ++ @Override ++ public boolean supportsBreakingDoors() { ++ return true; // All zombies are now capable of breaking doors, see https://bugs.mojang.com/browse/MC-137053 ++ } + // Paper end + + @Override diff --git a/patches/server/0450-Fix-nerfed-slime-when-splitting.patch b/patches/server/0450-Fix-nerfed-slime-when-splitting.patch new file mode 100644 index 0000000000..c35358b895 --- /dev/null +++ b/patches/server/0450-Fix-nerfed-slime-when-splitting.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 24 Aug 2020 08:39:06 -0700 +Subject: [PATCH] Fix nerfed slime when splitting + + +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 26f4db572dc6c25a9815b8f352d8829e252fa1a2..129f0cbc0469cb2804db6088b53347d88d91f4eb 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java +@@ -250,6 +250,7 @@ public class Slime extends Mob implements Enemy { + float f3 = ((float) (l / 2) - 0.5F) * f1; + + Slime converted = this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, scoreboardteam), EntitySpawnReason.TRIGGERED, (entityslime) -> { // CraftBukkit ++ entityslime.aware = this.aware; // Paper - Fix nerfed slime when splitting + entityslime.setSize(j, true); + entityslime.moveTo(this.getX() + (double) f2, this.getY() + 0.5D, this.getZ() + (double) f3, this.random.nextFloat() * 360.0F, 0.0F); + // CraftBukkit start diff --git a/patches/server/0450-Zombie-API-breaking-doors.patch b/patches/server/0450-Zombie-API-breaking-doors.patch deleted file mode 100644 index b0741f110f..0000000000 --- a/patches/server/0450-Zombie-API-breaking-doors.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 18 Nov 2020 11:32:46 -0800 -Subject: [PATCH] Zombie API - breaking doors - -== AT == -public net.minecraft.world.entity.monster.Zombie supportsBreakDoorGoal()Z - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java -index 4412c913123f7521f449c98b60378e8d3b1671ce..dfc2b40e20069705f92d86a6898e3e8348bf4dcd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftZombie.java -@@ -122,6 +122,11 @@ public class CraftZombie extends CraftMonster implements Zombie { - public void setShouldBurnInDay(boolean shouldBurnInDay) { - getHandle().setShouldBurnInDay(shouldBurnInDay); - } -+ -+ @Override -+ public boolean supportsBreakingDoors() { -+ return true; // All zombies are now capable of breaking doors, see https://bugs.mojang.com/browse/MC-137053 -+ } - // Paper end - - @Override diff --git a/patches/server/0451-Add-EntityLoadCrossbowEvent.patch b/patches/server/0451-Add-EntityLoadCrossbowEvent.patch new file mode 100644 index 0000000000..be830ab067 --- /dev/null +++ b/patches/server/0451-Add-EntityLoadCrossbowEvent.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JRoy +Date: Wed, 7 Oct 2020 12:04:01 -0400 +Subject: [PATCH] Add EntityLoadCrossbowEvent + + +diff --git a/src/main/java/net/minecraft/world/item/CrossbowItem.java b/src/main/java/net/minecraft/world/item/CrossbowItem.java +index a81e2f1e5abc20a95c562c1b9b1f7af489eaaaab..be1902a307a54434644b242b429ad47c271d2a0c 100644 +--- a/src/main/java/net/minecraft/world/item/CrossbowItem.java ++++ b/src/main/java/net/minecraft/world/item/CrossbowItem.java +@@ -90,7 +90,14 @@ public class CrossbowItem extends ProjectileWeaponItem { + public boolean releaseUsing(ItemStack stack, Level world, LivingEntity user, int remainingUseTicks) { + int i = this.getUseDuration(stack, user) - remainingUseTicks; + float f = getPowerForTime(i, stack, user); +- if (f >= 1.0F && !isCharged(stack) && tryLoadProjectiles(user, stack)) { ++ // Paper start - Add EntityLoadCrossbowEvent ++ if (f >= 1.0F && !isCharged(stack)) { ++ final io.papermc.paper.event.entity.EntityLoadCrossbowEvent event = new io.papermc.paper.event.entity.EntityLoadCrossbowEvent(user.getBukkitLivingEntity(), stack.asBukkitMirror(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(user.getUsedItemHand())); ++ if (!event.callEvent() || !tryLoadProjectiles(user, stack, event.shouldConsumeItem()) || !event.shouldConsumeItem()) { ++ if (user instanceof ServerPlayer player) player.containerMenu.sendAllDataToRemote(); ++ return false; ++ } ++ // Paper end - Add EntityLoadCrossbowEvent + CrossbowItem.ChargingSounds chargingSounds = this.getChargingSounds(stack); + chargingSounds.end() + .ifPresent( +@@ -111,8 +118,14 @@ public class CrossbowItem extends ProjectileWeaponItem { + } + } + +- private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow) { +- List list = draw(crossbow, shooter.getProjectile(crossbow), shooter); ++ @io.papermc.paper.annotation.DoNotUse // Paper - Add EntityLoadCrossbowEvent ++ private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow) { ++ // Paper start - Add EntityLoadCrossbowEvent ++ return CrossbowItem.tryLoadProjectiles(shooter, crossbow, true); ++ } ++ private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow, boolean consume) { ++ List list = draw(crossbow, shooter.getProjectile(crossbow), shooter, consume); ++ // Paper end - Add EntityLoadCrossbowEvent + if (!list.isEmpty()) { + crossbow.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(list)); + return true; +diff --git a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java +index a7d0ac6513fd888e222b3128afc1a227ea91f1d2..78ba170a83f8c026bd110eae494c52577182ed61 100644 +--- a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java ++++ b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java +@@ -109,6 +109,11 @@ public abstract class ProjectileWeaponItem extends Item { + } + + protected static List draw(ItemStack stack, ItemStack projectileStack, LivingEntity shooter) { ++ // Paper start ++ return draw(stack, projectileStack, shooter, true); ++ } ++ protected static List draw(ItemStack stack, ItemStack projectileStack, LivingEntity shooter, boolean consume) { ++ // Paper end + if (projectileStack.isEmpty()) { + return List.of(); + } else { +@@ -128,7 +133,7 @@ public abstract class ProjectileWeaponItem extends Item { + ItemStack itemstack2 = projectileStack.copy(); + + for (int k = 0; k < j; ++k) { +- ItemStack itemstack3 = ProjectileWeaponItem.useAmmo(stack, k == 0 ? projectileStack : itemstack2, shooter, k > 0); ++ ItemStack itemstack3 = ProjectileWeaponItem.useAmmo(stack, k == 0 ? projectileStack : itemstack2, shooter, k > 0 || !consume); // Paper + + if (!itemstack3.isEmpty()) { + list.add(itemstack3); diff --git a/patches/server/0451-Fix-nerfed-slime-when-splitting.patch b/patches/server/0451-Fix-nerfed-slime-when-splitting.patch deleted file mode 100644 index c35358b895..0000000000 --- a/patches/server/0451-Fix-nerfed-slime-when-splitting.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 24 Aug 2020 08:39:06 -0700 -Subject: [PATCH] Fix nerfed slime when splitting - - -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 26f4db572dc6c25a9815b8f352d8829e252fa1a2..129f0cbc0469cb2804db6088b53347d88d91f4eb 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Slime.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java -@@ -250,6 +250,7 @@ public class Slime extends Mob implements Enemy { - float f3 = ((float) (l / 2) - 0.5F) * f1; - - Slime converted = this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, scoreboardteam), EntitySpawnReason.TRIGGERED, (entityslime) -> { // CraftBukkit -+ entityslime.aware = this.aware; // Paper - Fix nerfed slime when splitting - entityslime.setSize(j, true); - entityslime.moveTo(this.getX() + (double) f2, this.getY() + 0.5D, this.getZ() + (double) f3, this.random.nextFloat() * 360.0F, 0.0F); - // CraftBukkit start diff --git a/patches/server/0452-Add-EntityLoadCrossbowEvent.patch b/patches/server/0452-Add-EntityLoadCrossbowEvent.patch deleted file mode 100644 index be830ab067..0000000000 --- a/patches/server/0452-Add-EntityLoadCrossbowEvent.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JRoy -Date: Wed, 7 Oct 2020 12:04:01 -0400 -Subject: [PATCH] Add EntityLoadCrossbowEvent - - -diff --git a/src/main/java/net/minecraft/world/item/CrossbowItem.java b/src/main/java/net/minecraft/world/item/CrossbowItem.java -index a81e2f1e5abc20a95c562c1b9b1f7af489eaaaab..be1902a307a54434644b242b429ad47c271d2a0c 100644 ---- a/src/main/java/net/minecraft/world/item/CrossbowItem.java -+++ b/src/main/java/net/minecraft/world/item/CrossbowItem.java -@@ -90,7 +90,14 @@ public class CrossbowItem extends ProjectileWeaponItem { - public boolean releaseUsing(ItemStack stack, Level world, LivingEntity user, int remainingUseTicks) { - int i = this.getUseDuration(stack, user) - remainingUseTicks; - float f = getPowerForTime(i, stack, user); -- if (f >= 1.0F && !isCharged(stack) && tryLoadProjectiles(user, stack)) { -+ // Paper start - Add EntityLoadCrossbowEvent -+ if (f >= 1.0F && !isCharged(stack)) { -+ final io.papermc.paper.event.entity.EntityLoadCrossbowEvent event = new io.papermc.paper.event.entity.EntityLoadCrossbowEvent(user.getBukkitLivingEntity(), stack.asBukkitMirror(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(user.getUsedItemHand())); -+ if (!event.callEvent() || !tryLoadProjectiles(user, stack, event.shouldConsumeItem()) || !event.shouldConsumeItem()) { -+ if (user instanceof ServerPlayer player) player.containerMenu.sendAllDataToRemote(); -+ return false; -+ } -+ // Paper end - Add EntityLoadCrossbowEvent - CrossbowItem.ChargingSounds chargingSounds = this.getChargingSounds(stack); - chargingSounds.end() - .ifPresent( -@@ -111,8 +118,14 @@ public class CrossbowItem extends ProjectileWeaponItem { - } - } - -- private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow) { -- List list = draw(crossbow, shooter.getProjectile(crossbow), shooter); -+ @io.papermc.paper.annotation.DoNotUse // Paper - Add EntityLoadCrossbowEvent -+ private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow) { -+ // Paper start - Add EntityLoadCrossbowEvent -+ return CrossbowItem.tryLoadProjectiles(shooter, crossbow, true); -+ } -+ private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow, boolean consume) { -+ List list = draw(crossbow, shooter.getProjectile(crossbow), shooter, consume); -+ // Paper end - Add EntityLoadCrossbowEvent - if (!list.isEmpty()) { - crossbow.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(list)); - return true; -diff --git a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java -index a7d0ac6513fd888e222b3128afc1a227ea91f1d2..78ba170a83f8c026bd110eae494c52577182ed61 100644 ---- a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java -+++ b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java -@@ -109,6 +109,11 @@ public abstract class ProjectileWeaponItem extends Item { - } - - protected static List draw(ItemStack stack, ItemStack projectileStack, LivingEntity shooter) { -+ // Paper start -+ return draw(stack, projectileStack, shooter, true); -+ } -+ protected static List draw(ItemStack stack, ItemStack projectileStack, LivingEntity shooter, boolean consume) { -+ // Paper end - if (projectileStack.isEmpty()) { - return List.of(); - } else { -@@ -128,7 +133,7 @@ public abstract class ProjectileWeaponItem extends Item { - ItemStack itemstack2 = projectileStack.copy(); - - for (int k = 0; k < j; ++k) { -- ItemStack itemstack3 = ProjectileWeaponItem.useAmmo(stack, k == 0 ? projectileStack : itemstack2, shooter, k > 0); -+ ItemStack itemstack3 = ProjectileWeaponItem.useAmmo(stack, k == 0 ? projectileStack : itemstack2, shooter, k > 0 || !consume); // Paper - - if (!itemstack3.isEmpty()) { - list.add(itemstack3); diff --git a/patches/server/0452-Add-WorldGameRuleChangeEvent.patch b/patches/server/0452-Add-WorldGameRuleChangeEvent.patch new file mode 100644 index 0000000000..a35834efa7 --- /dev/null +++ b/patches/server/0452-Add-WorldGameRuleChangeEvent.patch @@ -0,0 +1,100 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 20 Dec 2020 16:41:44 -0800 +Subject: [PATCH] Add WorldGameRuleChangeEvent + + +diff --git a/src/main/java/net/minecraft/server/commands/GameRuleCommand.java b/src/main/java/net/minecraft/server/commands/GameRuleCommand.java +index 6fc70f07f9ba964ff6f5176367dab788decfc917..da0600ab3b0a983ac36cb777d21160bdaced7c52 100644 +--- a/src/main/java/net/minecraft/server/commands/GameRuleCommand.java ++++ b/src/main/java/net/minecraft/server/commands/GameRuleCommand.java +@@ -36,7 +36,7 @@ public class GameRuleCommand { + CommandSourceStack commandlistenerwrapper = (CommandSourceStack) context.getSource(); + T t0 = commandlistenerwrapper.getLevel().getGameRules().getRule(key); // CraftBukkit + +- t0.setFromArgument(context, "value"); ++ t0.setFromArgument(context, "value", key); // Paper - Add WorldGameRuleChangeEvent + commandlistenerwrapper.sendSuccess(() -> { + return Component.translatable("commands.gamerule.set", key.getId(), t0.toString()); + }, true); +diff --git a/src/main/java/net/minecraft/world/level/GameRules.java b/src/main/java/net/minecraft/world/level/GameRules.java +index 7ea92a0b0f5d4eb6bd873e61c42bc0499d5d2028..09299e45552eb998fd02123c3921c0653f85083d 100644 +--- a/src/main/java/net/minecraft/world/level/GameRules.java ++++ b/src/main/java/net/minecraft/world/level/GameRules.java +@@ -322,10 +322,10 @@ public class GameRules { + this.type = type; + } + +- protected abstract void updateFromArgument(CommandContext context, String name); ++ protected abstract void updateFromArgument(CommandContext context, String name, GameRules.Key gameRuleKey); // Paper - Add WorldGameRuleChangeEvent + +- public void setFromArgument(CommandContext context, String name) { +- this.updateFromArgument(context, name); ++ public void setFromArgument(CommandContext context, String name, GameRules.Key gameRuleKey) { // Paper - Add WorldGameRuleChangeEvent ++ this.updateFromArgument(context, name, gameRuleKey); // Paper - Add WorldGameRuleChangeEvent + this.onChanged(((CommandSourceStack) context.getSource()).getLevel()); // CraftBukkit - per-world + } + +@@ -383,8 +383,11 @@ public class GameRules { + } + + @Override +- protected void updateFromArgument(CommandContext context, String name) { +- this.value = BoolArgumentType.getBool(context, name); ++ protected void updateFromArgument(CommandContext context, String name, GameRules.Key gameRuleKey) { // Paper start - Add WorldGameRuleChangeEvent ++ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(BoolArgumentType.getBool(context, name))); ++ if (!event.callEvent()) return; ++ this.value = Boolean.parseBoolean(event.getValue()); ++ // Paper end - Add WorldGameRuleChangeEvent + } + + public boolean get() { +@@ -456,8 +459,11 @@ public class GameRules { + } + + @Override +- protected void updateFromArgument(CommandContext context, String name) { +- this.value = IntegerArgumentType.getInteger(context, name); ++ protected void updateFromArgument(CommandContext context, String name, GameRules.Key gameRuleKey) { // Paper start - Add WorldGameRuleChangeEvent ++ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(IntegerArgumentType.getInteger(context, name))); ++ if (!event.callEvent()) return; ++ this.value = Integer.parseInt(event.getValue()); ++ // Paper end - Add WorldGameRuleChangeEvent + } + + public int get() { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index b877904bd18c96a4a7e49fb3e1aba2b6109f15cd..69464a4fe467128121fe1a9ba08c9c7154e22c7f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1884,9 +1884,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { + if (rule == null || value == null) return false; + + if (!this.isGameRule(rule)) return false; ++ // Paper start - Add WorldGameRuleChangeEvent ++ GameRule gameRule = GameRule.getByName(rule); ++ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(this, null, gameRule, value); ++ if (!event.callEvent()) return false; ++ // Paper end - Add WorldGameRuleChangeEvent + + GameRules.Value handle = this.getHandle().getGameRules().getRule(this.getGameRulesNMS().get(rule)); +- handle.deserialize(value); ++ handle.deserialize(event.getValue()); // Paper - Add WorldGameRuleChangeEvent + handle.onChanged(this.getHandle()); + return true; + } +@@ -1921,9 +1926,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { + Preconditions.checkArgument(newValue != null, "GameRule value cannot be null"); + + if (!this.isGameRule(rule.getName())) return false; ++ // Paper start - Add WorldGameRuleChangeEvent ++ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(this, null, rule, String.valueOf(newValue)); ++ if (!event.callEvent()) return false; ++ // Paper end - Add WorldGameRuleChangeEvent + + GameRules.Value handle = this.getHandle().getGameRules().getRule(this.getGameRulesNMS().get(rule.getName())); +- handle.deserialize(newValue.toString()); ++ handle.deserialize(event.getValue()); // Paper - Add WorldGameRuleChangeEvent + handle.onChanged(this.getHandle()); + return true; + } diff --git a/patches/server/0453-Add-ServerResourcesReloadedEvent.patch b/patches/server/0453-Add-ServerResourcesReloadedEvent.patch new file mode 100644 index 0000000000..b6ef8ff126 --- /dev/null +++ b/patches/server/0453-Add-ServerResourcesReloadedEvent.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Dec 2020 20:04:01 -0800 +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 c036c391172ffb4b14b7a5f77776a68e3670775c..d6fe710a4e3784ba38776a0496eac7fa702aed88 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -2150,7 +2150,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop reloadResources(Collection dataPacks) { ++ return this.reloadResources(dataPacks, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN); ++ } ++ public CompletableFuture reloadResources(Collection dataPacks, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause cause) { ++ // Paper end - Add ServerResourcesReloadedEvent + CompletableFuture completablefuture = CompletableFuture.supplyAsync(() -> { + Stream stream = dataPacks.stream(); // CraftBukkit - decompile error + PackRepository resourcepackrepository = this.packRepository; +@@ -2185,6 +2191,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop dataPacks, CommandSourceStack source) { +- source.getServer().reloadResources(dataPacks).exceptionally((throwable) -> { ++ source.getServer().reloadResources(dataPacks, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.COMMAND).exceptionally((throwable) -> { // Paper - Add ServerResourcesReloadedEvent + ReloadCommand.LOGGER.warn("Failed to execute reload", throwable); + source.sendFailure(Component.translatable("commands.reload.failure")); + return null; +@@ -50,7 +50,7 @@ public class ReloadCommand { + WorldData savedata = minecraftserver.getWorldData(); + Collection collection = resourcepackrepository.getSelectedIds(); + Collection collection1 = ReloadCommand.discoverNewPacks(resourcepackrepository, savedata, collection); +- minecraftserver.reloadResources(collection1); ++ minecraftserver.reloadResources(collection1, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN); // Paper - Add ServerResourcesReloadedEvent + } + // CraftBukkit end + diff --git a/patches/server/0453-Add-WorldGameRuleChangeEvent.patch b/patches/server/0453-Add-WorldGameRuleChangeEvent.patch deleted file mode 100644 index a35834efa7..0000000000 --- a/patches/server/0453-Add-WorldGameRuleChangeEvent.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 20 Dec 2020 16:41:44 -0800 -Subject: [PATCH] Add WorldGameRuleChangeEvent - - -diff --git a/src/main/java/net/minecraft/server/commands/GameRuleCommand.java b/src/main/java/net/minecraft/server/commands/GameRuleCommand.java -index 6fc70f07f9ba964ff6f5176367dab788decfc917..da0600ab3b0a983ac36cb777d21160bdaced7c52 100644 ---- a/src/main/java/net/minecraft/server/commands/GameRuleCommand.java -+++ b/src/main/java/net/minecraft/server/commands/GameRuleCommand.java -@@ -36,7 +36,7 @@ public class GameRuleCommand { - CommandSourceStack commandlistenerwrapper = (CommandSourceStack) context.getSource(); - T t0 = commandlistenerwrapper.getLevel().getGameRules().getRule(key); // CraftBukkit - -- t0.setFromArgument(context, "value"); -+ t0.setFromArgument(context, "value", key); // Paper - Add WorldGameRuleChangeEvent - commandlistenerwrapper.sendSuccess(() -> { - return Component.translatable("commands.gamerule.set", key.getId(), t0.toString()); - }, true); -diff --git a/src/main/java/net/minecraft/world/level/GameRules.java b/src/main/java/net/minecraft/world/level/GameRules.java -index 7ea92a0b0f5d4eb6bd873e61c42bc0499d5d2028..09299e45552eb998fd02123c3921c0653f85083d 100644 ---- a/src/main/java/net/minecraft/world/level/GameRules.java -+++ b/src/main/java/net/minecraft/world/level/GameRules.java -@@ -322,10 +322,10 @@ public class GameRules { - this.type = type; - } - -- protected abstract void updateFromArgument(CommandContext context, String name); -+ protected abstract void updateFromArgument(CommandContext context, String name, GameRules.Key gameRuleKey); // Paper - Add WorldGameRuleChangeEvent - -- public void setFromArgument(CommandContext context, String name) { -- this.updateFromArgument(context, name); -+ public void setFromArgument(CommandContext context, String name, GameRules.Key gameRuleKey) { // Paper - Add WorldGameRuleChangeEvent -+ this.updateFromArgument(context, name, gameRuleKey); // Paper - Add WorldGameRuleChangeEvent - this.onChanged(((CommandSourceStack) context.getSource()).getLevel()); // CraftBukkit - per-world - } - -@@ -383,8 +383,11 @@ public class GameRules { - } - - @Override -- protected void updateFromArgument(CommandContext context, String name) { -- this.value = BoolArgumentType.getBool(context, name); -+ protected void updateFromArgument(CommandContext context, String name, GameRules.Key gameRuleKey) { // Paper start - Add WorldGameRuleChangeEvent -+ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(BoolArgumentType.getBool(context, name))); -+ if (!event.callEvent()) return; -+ this.value = Boolean.parseBoolean(event.getValue()); -+ // Paper end - Add WorldGameRuleChangeEvent - } - - public boolean get() { -@@ -456,8 +459,11 @@ public class GameRules { - } - - @Override -- protected void updateFromArgument(CommandContext context, String name) { -- this.value = IntegerArgumentType.getInteger(context, name); -+ protected void updateFromArgument(CommandContext context, String name, GameRules.Key gameRuleKey) { // Paper start - Add WorldGameRuleChangeEvent -+ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(IntegerArgumentType.getInteger(context, name))); -+ if (!event.callEvent()) return; -+ this.value = Integer.parseInt(event.getValue()); -+ // Paper end - Add WorldGameRuleChangeEvent - } - - public int get() { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index b877904bd18c96a4a7e49fb3e1aba2b6109f15cd..69464a4fe467128121fe1a9ba08c9c7154e22c7f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1884,9 +1884,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { - if (rule == null || value == null) return false; - - if (!this.isGameRule(rule)) return false; -+ // Paper start - Add WorldGameRuleChangeEvent -+ GameRule gameRule = GameRule.getByName(rule); -+ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(this, null, gameRule, value); -+ if (!event.callEvent()) return false; -+ // Paper end - Add WorldGameRuleChangeEvent - - GameRules.Value handle = this.getHandle().getGameRules().getRule(this.getGameRulesNMS().get(rule)); -- handle.deserialize(value); -+ handle.deserialize(event.getValue()); // Paper - Add WorldGameRuleChangeEvent - handle.onChanged(this.getHandle()); - return true; - } -@@ -1921,9 +1926,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { - Preconditions.checkArgument(newValue != null, "GameRule value cannot be null"); - - if (!this.isGameRule(rule.getName())) return false; -+ // Paper start - Add WorldGameRuleChangeEvent -+ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(this, null, rule, String.valueOf(newValue)); -+ if (!event.callEvent()) return false; -+ // Paper end - Add WorldGameRuleChangeEvent - - GameRules.Value handle = this.getHandle().getGameRules().getRule(this.getGameRulesNMS().get(rule.getName())); -- handle.deserialize(newValue.toString()); -+ handle.deserialize(event.getValue()); // Paper - Add WorldGameRuleChangeEvent - handle.onChanged(this.getHandle()); - return true; - } diff --git a/patches/server/0454-Add-ServerResourcesReloadedEvent.patch b/patches/server/0454-Add-ServerResourcesReloadedEvent.patch deleted file mode 100644 index b6ef8ff126..0000000000 --- a/patches/server/0454-Add-ServerResourcesReloadedEvent.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 2 Dec 2020 20:04:01 -0800 -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 c036c391172ffb4b14b7a5f77776a68e3670775c..d6fe710a4e3784ba38776a0496eac7fa702aed88 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2150,7 +2150,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop reloadResources(Collection dataPacks) { -+ return this.reloadResources(dataPacks, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN); -+ } -+ public CompletableFuture reloadResources(Collection dataPacks, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause cause) { -+ // Paper end - Add ServerResourcesReloadedEvent - CompletableFuture completablefuture = CompletableFuture.supplyAsync(() -> { - Stream stream = dataPacks.stream(); // CraftBukkit - decompile error - PackRepository resourcepackrepository = this.packRepository; -@@ -2185,6 +2191,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop dataPacks, CommandSourceStack source) { -- source.getServer().reloadResources(dataPacks).exceptionally((throwable) -> { -+ source.getServer().reloadResources(dataPacks, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.COMMAND).exceptionally((throwable) -> { // Paper - Add ServerResourcesReloadedEvent - ReloadCommand.LOGGER.warn("Failed to execute reload", throwable); - source.sendFailure(Component.translatable("commands.reload.failure")); - return null; -@@ -50,7 +50,7 @@ public class ReloadCommand { - WorldData savedata = minecraftserver.getWorldData(); - Collection collection = resourcepackrepository.getSelectedIds(); - Collection collection1 = ReloadCommand.discoverNewPacks(resourcepackrepository, savedata, collection); -- minecraftserver.reloadResources(collection1); -+ minecraftserver.reloadResources(collection1, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN); // Paper - Add ServerResourcesReloadedEvent - } - // CraftBukkit end - diff --git a/patches/server/0454-Add-world-settings-for-mobs-picking-up-loot.patch b/patches/server/0454-Add-world-settings-for-mobs-picking-up-loot.patch new file mode 100644 index 0000000000..284e61124a --- /dev/null +++ b/patches/server/0454-Add-world-settings-for-mobs-picking-up-loot.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 28 Nov 2020 18:43:52 -0800 +Subject: [PATCH] Add world settings for mobs picking up loot + + +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 b7b567192f14ca8bac24b533dcbb5b5bd4f5a3aa..7c80c79a87ec438d0891c5c977e162f272d80039 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -152,7 +152,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + this.populateDefaultEquipmentSlots(randomsource, difficulty); + this.populateDefaultEquipmentEnchantments(world, randomsource, difficulty); + this.reassessWeaponGoal(); +- this.setCanPickUpLoot(randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); ++ this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot + if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { + LocalDate localdate = LocalDate.now(); + int i = localdate.get(ChronoField.DAY_OF_MONTH); +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 c182bdcc5da5652f8b34b4cb8d28651cf79009fe..34e46a64b3638f749a571d080fd8e7ac1f57edba 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java +@@ -518,7 +518,7 @@ public class Zombie extends Monster { + float f = difficulty.getSpecialMultiplier(); + + if (spawnReason != EntitySpawnReason.CONVERSION) { +- this.setCanPickUpLoot(randomsource.nextFloat() < 0.55F * f); ++ this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.zombies || randomsource.nextFloat() < 0.55F * f); // Paper - Add world settings for mobs picking up loot + } + + if (object == null) { diff --git a/patches/server/0455-Add-BlockFailedDispenseEvent.patch b/patches/server/0455-Add-BlockFailedDispenseEvent.patch new file mode 100644 index 0000000000..7d8f896e06 --- /dev/null +++ b/patches/server/0455-Add-BlockFailedDispenseEvent.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TheViperShow <29604693+TheViperShow@users.noreply.github.com> +Date: Wed, 22 Apr 2020 09:40:38 +0200 +Subject: [PATCH] Add BlockFailedDispenseEvent + + +diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java +index 975c02461bb88d71a0e3efe91838fad3fd346587..d915ef1030728a3f6ff303977784097b712238d4 100644 +--- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java +@@ -98,8 +98,10 @@ public class DispenserBlock extends BaseEntityBlock { + int i = tileentitydispenser.getRandomSlot(world.random); + + if (i < 0) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFailedDispenseEvent(world, pos)) { // Paper - Add BlockFailedDispenseEvent + world.levelEvent(1001, pos, 0); + world.gameEvent((Holder) GameEvent.BLOCK_ACTIVATE, pos, GameEvent.Context.of(tileentitydispenser.getBlockState())); ++ } // Paper - Add BlockFailedDispenseEvent + } else { + ItemStack itemstack = tileentitydispenser.getItem(i); + DispenseItemBehavior idispensebehavior = this.getDispenseMethod(world, itemstack); +diff --git a/src/main/java/net/minecraft/world/level/block/DropperBlock.java b/src/main/java/net/minecraft/world/level/block/DropperBlock.java +index a08e8571f3a83afc80c2f1758a9029cd28ed6947..91b514967405115f22edf4255775361a672e5c2f 100644 +--- a/src/main/java/net/minecraft/world/level/block/DropperBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DropperBlock.java +@@ -60,6 +60,7 @@ public class DropperBlock extends DispenserBlock { + int i = tileentitydispenser.getRandomSlot(world.random); + + if (i < 0) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFailedDispenseEvent(world, pos)) // Paper - Add BlockFailedDispenseEvent + world.levelEvent(1001, pos, 0); + } else { + ItemStack itemstack = tileentitydispenser.getItem(i); +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index f8751bf07479d6619ec1acb19f84a9af00ecd308..696867479e74c3c94e4131f2bbb97c857ed5e9dd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -2125,4 +2125,12 @@ public class CraftEventFactory { + return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getPotion()); + } + // Paper end - WitchReadyPotionEvent ++ ++ // Paper start ++ public static boolean handleBlockFailedDispenseEvent(ServerLevel serverLevel, BlockPos pos) { ++ org.bukkit.block.Block block = CraftBlock.at(serverLevel, pos); ++ io.papermc.paper.event.block.BlockFailedDispenseEvent event = new io.papermc.paper.event.block.BlockFailedDispenseEvent(block); ++ return event.callEvent(); ++ } ++ // Paper end + } diff --git a/patches/server/0455-Add-world-settings-for-mobs-picking-up-loot.patch b/patches/server/0455-Add-world-settings-for-mobs-picking-up-loot.patch deleted file mode 100644 index 284e61124a..0000000000 --- a/patches/server/0455-Add-world-settings-for-mobs-picking-up-loot.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 28 Nov 2020 18:43:52 -0800 -Subject: [PATCH] Add world settings for mobs picking up loot - - -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 b7b567192f14ca8bac24b533dcbb5b5bd4f5a3aa..7c80c79a87ec438d0891c5c977e162f272d80039 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -152,7 +152,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - this.populateDefaultEquipmentSlots(randomsource, difficulty); - this.populateDefaultEquipmentEnchantments(world, randomsource, difficulty); - this.reassessWeaponGoal(); -- this.setCanPickUpLoot(randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); -+ this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot - if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { - LocalDate localdate = LocalDate.now(); - int i = localdate.get(ChronoField.DAY_OF_MONTH); -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 c182bdcc5da5652f8b34b4cb8d28651cf79009fe..34e46a64b3638f749a571d080fd8e7ac1f57edba 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -518,7 +518,7 @@ public class Zombie extends Monster { - float f = difficulty.getSpecialMultiplier(); - - if (spawnReason != EntitySpawnReason.CONVERSION) { -- this.setCanPickUpLoot(randomsource.nextFloat() < 0.55F * f); -+ this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.zombies || randomsource.nextFloat() < 0.55F * f); // Paper - Add world settings for mobs picking up loot - } - - if (object == null) { diff --git a/patches/server/0456-Add-BlockFailedDispenseEvent.patch b/patches/server/0456-Add-BlockFailedDispenseEvent.patch deleted file mode 100644 index 7d8f896e06..0000000000 --- a/patches/server/0456-Add-BlockFailedDispenseEvent.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TheViperShow <29604693+TheViperShow@users.noreply.github.com> -Date: Wed, 22 Apr 2020 09:40:38 +0200 -Subject: [PATCH] Add BlockFailedDispenseEvent - - -diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -index 975c02461bb88d71a0e3efe91838fad3fd346587..d915ef1030728a3f6ff303977784097b712238d4 100644 ---- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -@@ -98,8 +98,10 @@ public class DispenserBlock extends BaseEntityBlock { - int i = tileentitydispenser.getRandomSlot(world.random); - - if (i < 0) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFailedDispenseEvent(world, pos)) { // Paper - Add BlockFailedDispenseEvent - world.levelEvent(1001, pos, 0); - world.gameEvent((Holder) GameEvent.BLOCK_ACTIVATE, pos, GameEvent.Context.of(tileentitydispenser.getBlockState())); -+ } // Paper - Add BlockFailedDispenseEvent - } else { - ItemStack itemstack = tileentitydispenser.getItem(i); - DispenseItemBehavior idispensebehavior = this.getDispenseMethod(world, itemstack); -diff --git a/src/main/java/net/minecraft/world/level/block/DropperBlock.java b/src/main/java/net/minecraft/world/level/block/DropperBlock.java -index a08e8571f3a83afc80c2f1758a9029cd28ed6947..91b514967405115f22edf4255775361a672e5c2f 100644 ---- a/src/main/java/net/minecraft/world/level/block/DropperBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DropperBlock.java -@@ -60,6 +60,7 @@ public class DropperBlock extends DispenserBlock { - int i = tileentitydispenser.getRandomSlot(world.random); - - if (i < 0) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFailedDispenseEvent(world, pos)) // Paper - Add BlockFailedDispenseEvent - world.levelEvent(1001, pos, 0); - } else { - ItemStack itemstack = tileentitydispenser.getItem(i); -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index f8751bf07479d6619ec1acb19f84a9af00ecd308..696867479e74c3c94e4131f2bbb97c857ed5e9dd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -2125,4 +2125,12 @@ public class CraftEventFactory { - return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getPotion()); - } - // Paper end - WitchReadyPotionEvent -+ -+ // Paper start -+ public static boolean handleBlockFailedDispenseEvent(ServerLevel serverLevel, BlockPos pos) { -+ org.bukkit.block.Block block = CraftBlock.at(serverLevel, pos); -+ io.papermc.paper.event.block.BlockFailedDispenseEvent event = new io.papermc.paper.event.block.BlockFailedDispenseEvent(block); -+ return event.callEvent(); -+ } -+ // Paper end - } diff --git a/patches/server/0456-Add-PlayerLecternPageChangeEvent.patch b/patches/server/0456-Add-PlayerLecternPageChangeEvent.patch new file mode 100644 index 0000000000..15052d962d --- /dev/null +++ b/patches/server/0456-Add-PlayerLecternPageChangeEvent.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 23 Nov 2020 12:58:51 -0800 +Subject: [PATCH] Add PlayerLecternPageChangeEvent + + +diff --git a/src/main/java/net/minecraft/world/inventory/LecternMenu.java b/src/main/java/net/minecraft/world/inventory/LecternMenu.java +index 1b3119751617366cf753008d38be566cd7ee2453..df4ae5d37b9aa5b8fb26c5773a47a5a85f831982 100644 +--- a/src/main/java/net/minecraft/world/inventory/LecternMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/LecternMenu.java +@@ -64,6 +64,7 @@ public class LecternMenu extends AbstractContainerMenu { + @Override + public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) { + int j; ++ io.papermc.paper.event.player.PlayerLecternPageChangeEvent playerLecternPageChangeEvent; CraftInventoryLectern bukkitView; // Paper - Add PlayerLecternPageChangeEvent + + if (id >= 100) { + j = id - 100; +@@ -73,11 +74,25 @@ public class LecternMenu extends AbstractContainerMenu { + switch (id) { + case 1: + j = this.lecternData.get(0); +- this.setData(0, j - 1); ++ // Paper start - Add PlayerLecternPageChangeEvent ++ bukkitView = (CraftInventoryLectern) getBukkitView().getTopInventory(); ++ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.LEFT, j, j - 1); ++ if (!playerLecternPageChangeEvent.callEvent()) { ++ return false; ++ } ++ this.setData(0, playerLecternPageChangeEvent.getNewPage()); ++ // Paper end - Add PlayerLecternPageChangeEvent + return true; + case 2: + j = this.lecternData.get(0); +- this.setData(0, j + 1); ++ // Paper start - Add PlayerLecternPageChangeEvent ++ bukkitView = (CraftInventoryLectern) getBukkitView().getTopInventory(); ++ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.RIGHT, j, j + 1); ++ if (!playerLecternPageChangeEvent.callEvent()) { ++ return false; ++ } ++ this.setData(0, playerLecternPageChangeEvent.getNewPage()); ++ // Paper end - Add PlayerLecternPageChangeEvent + return true; + case 3: + if (!player.mayBuild()) { diff --git a/patches/server/0457-Add-PlayerLecternPageChangeEvent.patch b/patches/server/0457-Add-PlayerLecternPageChangeEvent.patch deleted file mode 100644 index 15052d962d..0000000000 --- a/patches/server/0457-Add-PlayerLecternPageChangeEvent.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 23 Nov 2020 12:58:51 -0800 -Subject: [PATCH] Add PlayerLecternPageChangeEvent - - -diff --git a/src/main/java/net/minecraft/world/inventory/LecternMenu.java b/src/main/java/net/minecraft/world/inventory/LecternMenu.java -index 1b3119751617366cf753008d38be566cd7ee2453..df4ae5d37b9aa5b8fb26c5773a47a5a85f831982 100644 ---- a/src/main/java/net/minecraft/world/inventory/LecternMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/LecternMenu.java -@@ -64,6 +64,7 @@ public class LecternMenu extends AbstractContainerMenu { - @Override - public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) { - int j; -+ io.papermc.paper.event.player.PlayerLecternPageChangeEvent playerLecternPageChangeEvent; CraftInventoryLectern bukkitView; // Paper - Add PlayerLecternPageChangeEvent - - if (id >= 100) { - j = id - 100; -@@ -73,11 +74,25 @@ public class LecternMenu extends AbstractContainerMenu { - switch (id) { - case 1: - j = this.lecternData.get(0); -- this.setData(0, j - 1); -+ // Paper start - Add PlayerLecternPageChangeEvent -+ bukkitView = (CraftInventoryLectern) getBukkitView().getTopInventory(); -+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.LEFT, j, j - 1); -+ if (!playerLecternPageChangeEvent.callEvent()) { -+ return false; -+ } -+ this.setData(0, playerLecternPageChangeEvent.getNewPage()); -+ // Paper end - Add PlayerLecternPageChangeEvent - return true; - case 2: - j = this.lecternData.get(0); -- this.setData(0, j + 1); -+ // Paper start - Add PlayerLecternPageChangeEvent -+ bukkitView = (CraftInventoryLectern) getBukkitView().getTopInventory(); -+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.RIGHT, j, j + 1); -+ if (!playerLecternPageChangeEvent.callEvent()) { -+ return false; -+ } -+ this.setData(0, playerLecternPageChangeEvent.getNewPage()); -+ // Paper end - Add PlayerLecternPageChangeEvent - return true; - case 3: - if (!player.mayBuild()) { diff --git a/patches/server/0457-Add-PlayerLoomPatternSelectEvent.patch b/patches/server/0457-Add-PlayerLoomPatternSelectEvent.patch new file mode 100644 index 0000000000..b523b29e0f --- /dev/null +++ b/patches/server/0457-Add-PlayerLoomPatternSelectEvent.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 25 Nov 2020 16:33:27 -0800 +Subject: [PATCH] Add PlayerLoomPatternSelectEvent + + +diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java +index 58470d8e9a4ceb1eca05b342481ed8260588e225..1b7cf165ab0818792870f43719a6324b282bb57a 100644 +--- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java +@@ -162,8 +162,32 @@ public class LoomMenu extends AbstractContainerMenu { + @Override + public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) { + if (id >= 0 && id < this.selectablePatterns.size()) { +- this.selectedBannerPatternIndex.set(id); +- this.setupResultSlot((Holder) this.selectablePatterns.get(id)); ++ // Paper start - Add PlayerLoomPatternSelectEvent ++ int selectablePatternIndex = id; ++ io.papermc.paper.event.player.PlayerLoomPatternSelectEvent event = new io.papermc.paper.event.player.PlayerLoomPatternSelectEvent((Player) player.getBukkitEntity(), ((CraftInventoryLoom) getBukkitView().getTopInventory()), org.bukkit.craftbukkit.block.banner.CraftPatternType.minecraftHolderToBukkit(this.selectablePatterns.get(selectablePatternIndex))); ++ if (!event.callEvent()) { ++ player.containerMenu.sendAllDataToRemote(); ++ return false; ++ } ++ final Holder eventPattern = org.bukkit.craftbukkit.block.banner.CraftPatternType.bukkitToMinecraftHolder(event.getPatternType()); ++ Holder selectedPattern = null; ++ for (int i = 0; i < this.selectablePatterns.size(); i++) { ++ final Holder holder = this.selectablePatterns.get(i); ++ if (eventPattern.equals(holder)) { ++ selectablePatternIndex = i; ++ selectedPattern = holder; ++ break; ++ } ++ } ++ if (selectedPattern == null) { ++ selectedPattern = eventPattern; ++ selectablePatternIndex = -1; ++ } ++ ++ player.containerMenu.sendAllDataToRemote(); ++ this.selectedBannerPatternIndex.set(selectablePatternIndex); ++ this.setupResultSlot(java.util.Objects.requireNonNull(selectedPattern, "selectedPattern was null, this is unexpected")); ++ // Paper end - Add PlayerLoomPatternSelectEvent + return true; + } else { + return false; diff --git a/patches/server/0458-Add-PlayerLoomPatternSelectEvent.patch b/patches/server/0458-Add-PlayerLoomPatternSelectEvent.patch deleted file mode 100644 index b523b29e0f..0000000000 --- a/patches/server/0458-Add-PlayerLoomPatternSelectEvent.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 25 Nov 2020 16:33:27 -0800 -Subject: [PATCH] Add PlayerLoomPatternSelectEvent - - -diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java -index 58470d8e9a4ceb1eca05b342481ed8260588e225..1b7cf165ab0818792870f43719a6324b282bb57a 100644 ---- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java -@@ -162,8 +162,32 @@ public class LoomMenu extends AbstractContainerMenu { - @Override - public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) { - if (id >= 0 && id < this.selectablePatterns.size()) { -- this.selectedBannerPatternIndex.set(id); -- this.setupResultSlot((Holder) this.selectablePatterns.get(id)); -+ // Paper start - Add PlayerLoomPatternSelectEvent -+ int selectablePatternIndex = id; -+ io.papermc.paper.event.player.PlayerLoomPatternSelectEvent event = new io.papermc.paper.event.player.PlayerLoomPatternSelectEvent((Player) player.getBukkitEntity(), ((CraftInventoryLoom) getBukkitView().getTopInventory()), org.bukkit.craftbukkit.block.banner.CraftPatternType.minecraftHolderToBukkit(this.selectablePatterns.get(selectablePatternIndex))); -+ if (!event.callEvent()) { -+ player.containerMenu.sendAllDataToRemote(); -+ return false; -+ } -+ final Holder eventPattern = org.bukkit.craftbukkit.block.banner.CraftPatternType.bukkitToMinecraftHolder(event.getPatternType()); -+ Holder selectedPattern = null; -+ for (int i = 0; i < this.selectablePatterns.size(); i++) { -+ final Holder holder = this.selectablePatterns.get(i); -+ if (eventPattern.equals(holder)) { -+ selectablePatternIndex = i; -+ selectedPattern = holder; -+ break; -+ } -+ } -+ if (selectedPattern == null) { -+ selectedPattern = eventPattern; -+ selectablePatternIndex = -1; -+ } -+ -+ player.containerMenu.sendAllDataToRemote(); -+ this.selectedBannerPatternIndex.set(selectablePatternIndex); -+ this.setupResultSlot(java.util.Objects.requireNonNull(selectedPattern, "selectedPattern was null, this is unexpected")); -+ // Paper end - Add PlayerLoomPatternSelectEvent - return true; - } else { - return false; diff --git a/patches/server/0458-Configurable-door-breaking-difficulty.patch b/patches/server/0458-Configurable-door-breaking-difficulty.patch new file mode 100644 index 0000000000..94b37c735f --- /dev/null +++ b/patches/server/0458-Configurable-door-breaking-difficulty.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 3 Jan 2021 22:27:43 -0800 +Subject: [PATCH] Configurable door breaking difficulty + +== AT == +public net.minecraft.world.entity.monster.Vindicator DOOR_BREAKING_PREDICATE +public net.minecraft.world.entity.monster.Zombie DOOR_BREAKING_PREDICATE + +Co-authored-by: Doc + +diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java +index b06eedb1cb13771bbc7d0b812a9df864d1f73142..96b105697c91314148fd1b783501389214b1a3f0 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java +@@ -184,7 +184,7 @@ public class Vindicator extends AbstractIllager { + + static class VindicatorBreakDoorGoal extends BreakDoorGoal { + public VindicatorBreakDoorGoal(Mob mob) { +- super(mob, 6, Vindicator.DOOR_BREAKING_PREDICATE); ++ super(mob, 6, com.google.common.base.Predicates.in(mob.level().paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(mob.getType(), mob.level().paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.VINDICATOR)))); // Paper - Configurable door breaking difficulty + this.setFlags(EnumSet.of(Goal.Flag.MOVE)); + } + +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 34e46a64b3638f749a571d080fd8e7ac1f57edba..a835ec6e063dd247a008da84446f8647f38d89d4 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java +@@ -103,7 +103,7 @@ public class Zombie extends Monster { + + public Zombie(EntityType type, Level world) { + super(type, world); +- this.breakDoorGoal = new BreakDoorGoal(this, Zombie.DOOR_BREAKING_PREDICATE); ++ this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(world.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(type, world.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty + } + + public Zombie(Level world) { diff --git a/patches/server/0459-Configurable-door-breaking-difficulty.patch b/patches/server/0459-Configurable-door-breaking-difficulty.patch deleted file mode 100644 index 94b37c735f..0000000000 --- a/patches/server/0459-Configurable-door-breaking-difficulty.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 3 Jan 2021 22:27:43 -0800 -Subject: [PATCH] Configurable door breaking difficulty - -== AT == -public net.minecraft.world.entity.monster.Vindicator DOOR_BREAKING_PREDICATE -public net.minecraft.world.entity.monster.Zombie DOOR_BREAKING_PREDICATE - -Co-authored-by: Doc - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -index b06eedb1cb13771bbc7d0b812a9df864d1f73142..96b105697c91314148fd1b783501389214b1a3f0 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -@@ -184,7 +184,7 @@ public class Vindicator extends AbstractIllager { - - static class VindicatorBreakDoorGoal extends BreakDoorGoal { - public VindicatorBreakDoorGoal(Mob mob) { -- super(mob, 6, Vindicator.DOOR_BREAKING_PREDICATE); -+ super(mob, 6, com.google.common.base.Predicates.in(mob.level().paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(mob.getType(), mob.level().paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.VINDICATOR)))); // Paper - Configurable door breaking difficulty - this.setFlags(EnumSet.of(Goal.Flag.MOVE)); - } - -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 34e46a64b3638f749a571d080fd8e7ac1f57edba..a835ec6e063dd247a008da84446f8647f38d89d4 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -103,7 +103,7 @@ public class Zombie extends Monster { - - public Zombie(EntityType type, Level world) { - super(type, world); -- this.breakDoorGoal = new BreakDoorGoal(this, Zombie.DOOR_BREAKING_PREDICATE); -+ this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(world.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(type, world.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty - } - - public Zombie(Level world) { diff --git a/patches/server/0459-Empty-commands-shall-not-be-dispatched.patch b/patches/server/0459-Empty-commands-shall-not-be-dispatched.patch new file mode 100644 index 0000000000..9d321da35f --- /dev/null +++ b/patches/server/0459-Empty-commands-shall-not-be-dispatched.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Wed, 6 Jan 2021 23:38:43 +0100 +Subject: [PATCH] Empty commands shall not be dispatched + + +diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java +index b34abf66c7dc756e88e08637af976f7794144d06..2dcb1a1bdba1d1cad3caa117d85a8619ed9e67b4 100644 +--- a/src/main/java/net/minecraft/commands/Commands.java ++++ b/src/main/java/net/minecraft/commands/Commands.java +@@ -291,6 +291,7 @@ public class Commands { + command = event.getCommand(); + + 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()); diff --git a/patches/server/0460-Empty-commands-shall-not-be-dispatched.patch b/patches/server/0460-Empty-commands-shall-not-be-dispatched.patch deleted file mode 100644 index 9d321da35f..0000000000 --- a/patches/server/0460-Empty-commands-shall-not-be-dispatched.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Wed, 6 Jan 2021 23:38:43 +0100 -Subject: [PATCH] Empty commands shall not be dispatched - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index b34abf66c7dc756e88e08637af976f7794144d06..2dcb1a1bdba1d1cad3caa117d85a8619ed9e67b4 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -291,6 +291,7 @@ public class Commands { - command = event.getCommand(); - - 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()); diff --git a/patches/server/0460-Remove-stale-POIs.patch b/patches/server/0460-Remove-stale-POIs.patch new file mode 100644 index 0000000000..2c29fc65e4 --- /dev/null +++ b/patches/server/0460-Remove-stale-POIs.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sat, 9 Jan 2021 14:17:07 +0100 +Subject: [PATCH] Remove stale POIs + + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index f6b91771445ab4f48525f24025a9f5249f176cd5..412c1af3282d5d5bbcb7276c6cf90e9ce87668ba 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1790,6 +1790,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + }); + optional1.ifPresent((holder) -> { + this.getServer().execute(() -> { ++ // Paper start - Remove stale POIs ++ if (optional.isEmpty() && this.getPoiManager().exists(blockposition1, poiType -> true)) { ++ this.getPoiManager().remove(blockposition1); ++ } ++ // Paper end - Remove stale POIs + this.getPoiManager().add(blockposition1, holder); + DebugPackets.sendPoiAddedPacket(this, blockposition1); + }); diff --git a/patches/server/0461-Fix-villager-boat-exploit.patch b/patches/server/0461-Fix-villager-boat-exploit.patch new file mode 100644 index 0000000000..8a06e563da --- /dev/null +++ b/patches/server/0461-Fix-villager-boat-exploit.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Mon, 11 Jan 2021 12:43:51 -0800 +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 e734798640cc016d54c56b7870a1a653353ff709..4a86a15b009412208247edd7bb8e4655f92da5d1 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -544,6 +544,14 @@ public abstract class PlayerList { + PlayerList.LOGGER.debug("Removing player mount"); + entityplayer.stopRiding(); + entity.getPassengersAndSelf().forEach((entity1) -> { ++ // Paper start - Fix villager boat exploit ++ if (entity1 instanceof net.minecraft.world.entity.npc.AbstractVillager villager) { ++ final net.minecraft.world.entity.player.Player human = villager.getTradingPlayer(); ++ if (human != null) { ++ villager.setTradingPlayer(null); ++ } ++ } ++ // Paper end - Fix villager boat exploit + entity1.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause + }); + } diff --git a/patches/server/0461-Remove-stale-POIs.patch b/patches/server/0461-Remove-stale-POIs.patch deleted file mode 100644 index 2c29fc65e4..0000000000 --- a/patches/server/0461-Remove-stale-POIs.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sat, 9 Jan 2021 14:17:07 +0100 -Subject: [PATCH] Remove stale POIs - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index f6b91771445ab4f48525f24025a9f5249f176cd5..412c1af3282d5d5bbcb7276c6cf90e9ce87668ba 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1790,6 +1790,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - }); - optional1.ifPresent((holder) -> { - this.getServer().execute(() -> { -+ // Paper start - Remove stale POIs -+ if (optional.isEmpty() && this.getPoiManager().exists(blockposition1, poiType -> true)) { -+ this.getPoiManager().remove(blockposition1); -+ } -+ // Paper end - Remove stale POIs - this.getPoiManager().add(blockposition1, holder); - DebugPackets.sendPoiAddedPacket(this, blockposition1); - }); diff --git a/patches/server/0462-Add-sendOpLevel-API.patch b/patches/server/0462-Add-sendOpLevel-API.patch new file mode 100644 index 0000000000..df8490e384 --- /dev/null +++ b/patches/server/0462-Add-sendOpLevel-API.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Tue, 29 Dec 2020 15:03:03 +0100 +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 4a86a15b009412208247edd7bb8e4655f92da5d1..f023959eee56d8d37cf0a76cb7352c0045cd2ea0 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 { + } + + private void sendPlayerPermissionLevel(ServerPlayer player, int permissionLevel) { ++ // Paper start - Add sendOpLevel API ++ this.sendPlayerPermissionLevel(player, permissionLevel, true); ++ } ++ public void sendPlayerPermissionLevel(ServerPlayer player, int permissionLevel, boolean recalculatePermissions) { ++ // Paper end - Add sendOpLevel API + if (player.connection != null) { + byte b0; + +@@ -1040,8 +1045,10 @@ public abstract class PlayerList { + player.connection.send(new ClientboundEntityEventPacket(player, b0)); + } + ++ if (recalculatePermissions) { // Paper - Add sendOpLevel API + player.getBukkitEntity().recalculatePermissions(); // CraftBukkit + this.server.getCommands().sendCommands(player); ++ } // Paper - Add sendOpLevel API + } + + public boolean isWhiteListed(GameProfile profile) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 0aaea6091c5828782ed606d250423f3d75b9b27f..c93ec7e97c9af44ed75e7ea4fb1c6c58c2b6bc1a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -684,6 +684,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + // Paper end + ++ // Paper start - Add sendOpLevel API ++ @Override ++ public void sendOpLevel(byte level) { ++ Preconditions.checkArgument(level >= 0 && level <= 4, "Level must be within [0, 4]"); ++ ++ this.getHandle().getServer().getPlayerList().sendPlayerPermissionLevel(this.getHandle(), level, false); ++ } ++ // Paper end - Add sendOpLevel API ++ + @Override + public void setCompassTarget(Location loc) { + Preconditions.checkArgument(loc != null, "Location cannot be null"); diff --git a/patches/server/0462-Fix-villager-boat-exploit.patch b/patches/server/0462-Fix-villager-boat-exploit.patch deleted file mode 100644 index 8a06e563da..0000000000 --- a/patches/server/0462-Fix-villager-boat-exploit.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Mon, 11 Jan 2021 12:43:51 -0800 -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 e734798640cc016d54c56b7870a1a653353ff709..4a86a15b009412208247edd7bb8e4655f92da5d1 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -544,6 +544,14 @@ public abstract class PlayerList { - PlayerList.LOGGER.debug("Removing player mount"); - entityplayer.stopRiding(); - entity.getPassengersAndSelf().forEach((entity1) -> { -+ // Paper start - Fix villager boat exploit -+ if (entity1 instanceof net.minecraft.world.entity.npc.AbstractVillager villager) { -+ final net.minecraft.world.entity.player.Player human = villager.getTradingPlayer(); -+ if (human != null) { -+ villager.setTradingPlayer(null); -+ } -+ } -+ // Paper end - Fix villager boat exploit - entity1.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause - }); - } diff --git a/patches/server/0463-Add-RegistryAccess-for-managing-Registries.patch b/patches/server/0463-Add-RegistryAccess-for-managing-Registries.patch new file mode 100644 index 0000000000..9c82b85992 --- /dev/null +++ b/patches/server/0463-Add-RegistryAccess-for-managing-Registries.patch @@ -0,0 +1,1405 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 27 Feb 2023 18:28:39 -0800 +Subject: [PATCH] Add RegistryAccess for managing Registries + +RegistryAccess is independant from CraftServer and +doesn't require one to be created allowing the +org.bukkit.Registry class to be loaded earlier. + +== AT == +public net.minecraft.server.RegistryLayer STATIC_ACCESS + +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cd8a6a4c2a63029f8f859765088c227bbd456813 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +@@ -0,0 +1,154 @@ ++package io.papermc.paper.registry; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.registry.entry.RegistryEntry; ++import java.util.Collections; ++import java.util.IdentityHashMap; ++import java.util.List; ++import java.util.Map; ++import java.util.Objects; ++import net.minecraft.core.Registry; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Art; ++import org.bukkit.Fluid; ++import org.bukkit.GameEvent; ++import org.bukkit.JukeboxSong; ++import org.bukkit.Keyed; ++import org.bukkit.MusicInstrument; ++import org.bukkit.Sound; ++import org.bukkit.attribute.Attribute; ++import org.bukkit.block.Biome; ++import org.bukkit.block.BlockType; ++import org.bukkit.block.banner.PatternType; ++import org.bukkit.craftbukkit.CraftArt; ++import org.bukkit.craftbukkit.CraftFluid; ++import org.bukkit.craftbukkit.CraftGameEvent; ++import org.bukkit.craftbukkit.CraftJukeboxSong; ++import org.bukkit.craftbukkit.CraftMusicInstrument; ++import org.bukkit.craftbukkit.CraftSound; ++import org.bukkit.craftbukkit.attribute.CraftAttribute; ++import org.bukkit.craftbukkit.block.CraftBiome; ++import org.bukkit.craftbukkit.block.CraftBlockType; ++import org.bukkit.craftbukkit.block.banner.CraftPatternType; ++import org.bukkit.craftbukkit.damage.CraftDamageType; ++import org.bukkit.craftbukkit.enchantments.CraftEnchantment; ++import org.bukkit.craftbukkit.entity.CraftCat; ++import org.bukkit.craftbukkit.entity.CraftFrog; ++import org.bukkit.craftbukkit.entity.CraftVillager; ++import org.bukkit.craftbukkit.entity.CraftWolf; ++import org.bukkit.craftbukkit.generator.structure.CraftStructure; ++import org.bukkit.craftbukkit.generator.structure.CraftStructureType; ++import org.bukkit.craftbukkit.inventory.CraftItemType; ++import org.bukkit.craftbukkit.inventory.CraftMenuType; ++import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial; ++import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern; ++import org.bukkit.craftbukkit.legacy.FieldRename; ++import org.bukkit.craftbukkit.map.CraftMapCursor; ++import org.bukkit.craftbukkit.potion.CraftPotionEffectType; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.damage.DamageType; ++import org.bukkit.enchantments.Enchantment; ++import org.bukkit.entity.Cat; ++import org.bukkit.entity.Frog; ++import org.bukkit.entity.Villager; ++import org.bukkit.entity.Wolf; ++import org.bukkit.entity.memory.MemoryKey; ++import org.bukkit.generator.structure.Structure; ++import org.bukkit.generator.structure.StructureType; ++import org.bukkit.inventory.ItemType; ++import org.bukkit.inventory.MenuType; ++import org.bukkit.inventory.meta.trim.TrimMaterial; ++import org.bukkit.inventory.meta.trim.TrimPattern; ++import org.bukkit.map.MapCursor; ++import org.bukkit.potion.PotionEffectType; ++import org.jspecify.annotations.Nullable; ++ ++import static io.papermc.paper.registry.entry.RegistryEntry.apiOnly; ++import static io.papermc.paper.registry.entry.RegistryEntry.entry; ++ ++public final class PaperRegistries { ++ ++ static final List> REGISTRY_ENTRIES; ++ private static final Map, RegistryEntry> BY_REGISTRY_KEY; ++ private static final Map, RegistryEntry> BY_RESOURCE_KEY; ++ static { ++ REGISTRY_ENTRIES = List.of( ++ // built-ins ++ entry(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new), ++ entry(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new), ++ entry(Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, PotionEffectType.class, CraftPotionEffectType::new), ++ entry(Registries.BLOCK, RegistryKey.BLOCK, BlockType.class, CraftBlockType::new), ++ entry(Registries.ITEM, RegistryKey.ITEM, ItemType.class, CraftItemType::new), ++ entry(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT, Cat.Type.class, CraftCat.CraftType::new), ++ entry(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT, Frog.Variant.class, CraftFrog.CraftVariant::new), ++ entry(Registries.VILLAGER_PROFESSION, RegistryKey.VILLAGER_PROFESSION, Villager.Profession.class, CraftVillager.CraftProfession::new), ++ entry(Registries.VILLAGER_TYPE, RegistryKey.VILLAGER_TYPE, Villager.Type.class, CraftVillager.CraftType::new), ++ entry(Registries.MAP_DECORATION_TYPE, RegistryKey.MAP_DECORATION_TYPE, MapCursor.Type.class, CraftMapCursor.CraftType::new), ++ entry(Registries.MENU, RegistryKey.MENU, MenuType.class, CraftMenuType::new), ++ entry(Registries.ATTRIBUTE, RegistryKey.ATTRIBUTE, Attribute.class, CraftAttribute::new), ++ entry(Registries.FLUID, RegistryKey.FLUID, Fluid.class, CraftFluid::new), ++ entry(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT, Sound.class, CraftSound::new), ++ ++ // data-drivens ++ entry(Registries.BIOME, RegistryKey.BIOME, Biome.class, CraftBiome::new).delayed(), ++ entry(Registries.STRUCTURE, RegistryKey.STRUCTURE, Structure.class, CraftStructure::new).delayed(), ++ entry(Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL, TrimMaterial.class, CraftTrimMaterial::new).delayed(), ++ entry(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN, TrimPattern.class, CraftTrimPattern::new).delayed(), ++ entry(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE, DamageType.class, CraftDamageType::new).delayed(), ++ entry(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT, Wolf.Variant.class, CraftWolf.CraftVariant::new).delayed(), ++ entry(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, Enchantment.class, CraftEnchantment::new).withSerializationUpdater(FieldRename.ENCHANTMENT_RENAME).delayed(), ++ entry(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG, JukeboxSong.class, CraftJukeboxSong::new).delayed(), ++ entry(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN, PatternType.class, CraftPatternType::new).delayed(), ++ entry(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT, Art.class, CraftArt::new).delayed(), ++ entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new).delayed(), ++ ++ // api-only ++ apiOnly(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE, PaperSimpleRegistry::entityType), ++ apiOnly(Registries.PARTICLE_TYPE, RegistryKey.PARTICLE_TYPE, PaperSimpleRegistry::particleType), ++ apiOnly(Registries.POTION, RegistryKey.POTION, PaperSimpleRegistry::potion), ++ apiOnly(Registries.MEMORY_MODULE_TYPE, RegistryKey.MEMORY_MODULE_TYPE, () -> (org.bukkit.Registry>) (org.bukkit.Registry) org.bukkit.Registry.MEMORY_MODULE_TYPE) ++ ); ++ final Map, RegistryEntry> byRegistryKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); ++ final Map, RegistryEntry> byResourceKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); ++ for (final RegistryEntry entry : REGISTRY_ENTRIES) { ++ Preconditions.checkState(byRegistryKey.put(entry.apiKey(), entry) == null, "Duplicate api registry key: %s", entry.apiKey()); ++ Preconditions.checkState(byResourceKey.put(entry.mcKey(), entry) == null, "Duplicate mc registry key: %s", entry.mcKey()); ++ } ++ BY_REGISTRY_KEY = Collections.unmodifiableMap(byRegistryKey); ++ BY_RESOURCE_KEY = Collections.unmodifiableMap(byResourceKey); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static @Nullable RegistryEntry getEntry(final ResourceKey> resourceKey) { ++ return (RegistryEntry) BY_RESOURCE_KEY.get(resourceKey); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static @Nullable RegistryEntry getEntry(final RegistryKey registryKey) { ++ return (RegistryEntry) BY_REGISTRY_KEY.get(registryKey); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static RegistryKey registryFromNms(final ResourceKey> registryResourceKey) { ++ return (RegistryKey) Objects.requireNonNull(BY_RESOURCE_KEY.get(registryResourceKey), registryResourceKey + " doesn't have an api RegistryKey").apiKey(); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static ResourceKey> registryToNms(final RegistryKey registryKey) { ++ return (ResourceKey>) Objects.requireNonNull(BY_REGISTRY_KEY.get(registryKey), registryKey + " doesn't have an mc registry ResourceKey").mcKey(); ++ } ++ ++ public static TypedKey fromNms(final ResourceKey resourceKey) { ++ return TypedKey.create(registryFromNms(resourceKey.registryKey()), CraftNamespacedKey.fromMinecraft(resourceKey.location())); ++ } ++ ++ @SuppressWarnings({"unchecked", "RedundantCast"}) ++ public static ResourceKey toNms(final TypedKey typedKey) { ++ return ResourceKey.create((ResourceKey>) PaperRegistries.registryToNms(typedKey.registryKey()), PaperAdventure.asVanilla(typedKey.key())); ++ } ++ ++ private PaperRegistries() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4bf7915867dbe762ef0b070d67d5f7b7d1ee4f03 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +@@ -0,0 +1,122 @@ ++package io.papermc.paper.registry; ++ ++import io.papermc.paper.registry.entry.ApiRegistryEntry; ++import io.papermc.paper.registry.entry.RegistryEntry; ++import io.papermc.paper.registry.legacy.DelayedRegistry; ++import io.papermc.paper.registry.legacy.DelayedRegistryEntry; ++import io.papermc.paper.registry.legacy.LegacyRegistryIdentifiers; ++import java.util.Map; ++import java.util.NoSuchElementException; ++import java.util.Set; ++import java.util.concurrent.ConcurrentHashMap; ++import java.util.stream.Collectors; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.VisibleForTesting; ++import org.jspecify.annotations.Nullable; ++ ++public class PaperRegistryAccess implements RegistryAccess { ++ ++ // We store the API registries in a memoized supplier, so they can be created on-demand. ++ // These suppliers are added to this map right after the instance of nms.Registry is created before it is loaded. ++ // We want to do registration there, so we have access to the nms.Registry instance in order to wrap it in a CraftRegistry instance. ++ // The memoized Supplier is needed because we *can't* instantiate any CraftRegistry class until **all** the BuiltInRegistries have been added ++ // to this map because that would class-load org.bukkit.Registry which would query this map. ++ private final Map, RegistryHolder> registries = new ConcurrentHashMap<>(); // is "identity" because RegistryKey overrides equals and hashCode ++ ++ public static PaperRegistryAccess instance() { ++ return (PaperRegistryAccess) RegistryAccessHolder.INSTANCE.orElseThrow(() -> new IllegalStateException("No RegistryAccess implementation found")); ++ } ++ ++ @VisibleForTesting ++ public Set> getLoadedServerBackedRegistries() { ++ return this.registries.keySet().stream().filter(registryHolder -> !(PaperRegistries.getEntry(registryHolder) instanceof ApiRegistryEntry)).collect(Collectors.toUnmodifiableSet()); ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Deprecated(forRemoval = true) ++ @Override ++ public @Nullable Registry getRegistry(final Class type) { ++ final RegistryKey registryKey = byType(type); ++ // If our mapping from Class -> RegistryKey did not contain the passed type it was either a completely invalid type or a registry ++ // that merely exists as a SimpleRegistry in the org.bukkit.Registry type. We cannot return a registry for these, return null ++ // as per method contract in Bukkit#getRegistry. ++ if (registryKey == null) return null; ++ ++ final RegistryEntry entry = PaperRegistries.getEntry(registryKey); ++ final RegistryHolder registry = (RegistryHolder) this.registries.get(registryKey); ++ if (registry != null) { ++ // if the registry exists, return right away. Since this is the "legacy" method, we return DelayedRegistry ++ // for the non-builtin Registry instances stored as fields in Registry. ++ return registry.get(); ++ } else if (entry instanceof DelayedRegistryEntry) { ++ // if the registry doesn't exist and the entry is marked as "delayed", we create a registry holder that is empty ++ // which will later be filled with the actual registry. This is so the fields on org.bukkit.Registry can be populated with ++ // registries that don't exist at the time org.bukkit.Registry is statically initialized. ++ final RegistryHolder delayedHolder = new RegistryHolder.Delayed<>(); ++ this.registries.put(registryKey, delayedHolder); ++ return delayedHolder.get(); ++ } else { ++ // if the registry doesn't exist yet or doesn't have a delayed entry, just return null ++ return null; ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Override ++ public Registry getRegistry(final RegistryKey key) { ++ if (PaperRegistries.getEntry(key) == null) { ++ throw new NoSuchElementException(key + " is not a valid registry key"); ++ } ++ final @Nullable RegistryHolder registryHolder = (RegistryHolder) this.registries.get(key); ++ if (registryHolder == null) { ++ throw new IllegalArgumentException(key + " points to a registry that is not available yet"); ++ } ++ // since this is the getRegistry method that uses the modern RegistryKey, we unwrap any DelayedRegistry instances ++ // that might be returned here. I don't think reference equality is required when doing getRegistry(RegistryKey.WOLF_VARIANT) == Registry.WOLF_VARIANT ++ return possiblyUnwrap(registryHolder.get()); ++ } ++ ++ private static Registry possiblyUnwrap(final Registry registry) { ++ if (registry instanceof final DelayedRegistry delayedRegistry) { // if not coming from legacy, unwrap the delayed registry ++ return delayedRegistry.delegate(); ++ } ++ return registry; ++ } ++ ++ public void registerReloadableRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry) { ++ this.registerRegistry(resourceKey, registry, true); ++ } ++ ++ public void registerRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry) { ++ this.registerRegistry(resourceKey, registry, false); ++ } ++ ++ @SuppressWarnings("unchecked") // this method should be called right after any new MappedRegistry instances are created to later be used by the server. ++ private > void registerRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry, final boolean replace) { ++ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(resourceKey); ++ if (entry == null) { // skip registries that don't have API entries ++ return; ++ } ++ final @Nullable RegistryHolder registryHolder = (RegistryHolder) this.registries.get(entry.apiKey()); ++ if (registryHolder == null || replace) { ++ // if the holder doesn't exist yet, or is marked as "replaceable", put it in the map. ++ this.registries.put(entry.apiKey(), entry.createRegistryHolder(registry)); ++ } else { ++ if (registryHolder instanceof RegistryHolder.Delayed && entry instanceof final DelayedRegistryEntry delayedEntry) { ++ // if the registry holder is delayed, and the entry is marked as "delayed", then load the holder with the CraftRegistry instance that wraps the actual nms Registry. ++ ((RegistryHolder.Delayed) registryHolder).loadFrom(delayedEntry, registry); ++ } else { ++ throw new IllegalArgumentException(resourceKey + " has already been created"); ++ } ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Deprecated ++ @VisibleForTesting ++ public static @Nullable RegistryKey byType(final Class type) { ++ return (RegistryKey) LegacyRegistryIdentifiers.CLASS_TO_KEY_MAP.get(type); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6d134ace042758da722960cbcb48e52508dafd61 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java +@@ -0,0 +1,38 @@ ++package io.papermc.paper.registry; ++ ++import java.util.function.Predicate; ++import net.minecraft.core.registries.BuiltInRegistries; ++import org.bukkit.Keyed; ++import org.bukkit.Particle; ++import org.bukkit.Registry; ++import org.bukkit.entity.EntityType; ++import org.bukkit.potion.PotionType; ++import org.jspecify.annotations.NullMarked; ++ ++@NullMarked ++public class PaperSimpleRegistry & Keyed, M> extends Registry.SimpleRegistry { ++ ++ static Registry entityType() { ++ return new PaperSimpleRegistry<>(EntityType.class, entity -> entity != EntityType.UNKNOWN, BuiltInRegistries.ENTITY_TYPE); ++ } ++ ++ static Registry particleType() { ++ return new PaperSimpleRegistry<>(Particle.class, BuiltInRegistries.PARTICLE_TYPE); ++ } ++ ++ static Registry potion() { ++ return new PaperSimpleRegistry<>(PotionType.class, BuiltInRegistries.POTION); ++ } ++ ++ private final net.minecraft.core.Registry nmsRegistry; ++ ++ protected PaperSimpleRegistry(final Class type, final net.minecraft.core.Registry nmsRegistry) { ++ super(type); ++ this.nmsRegistry = nmsRegistry; ++ } ++ ++ public PaperSimpleRegistry(final Class type, final Predicate predicate, final net.minecraft.core.Registry nmsRegistry) { ++ super(type, predicate); ++ this.nmsRegistry = nmsRegistry; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryHolder.java b/src/main/java/io/papermc/paper/registry/RegistryHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1b52d4bc868e1e5f84c8416301e193bb9cd315b2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryHolder.java +@@ -0,0 +1,44 @@ ++package io.papermc.paper.registry; ++ ++import com.google.common.base.Suppliers; ++import io.papermc.paper.registry.legacy.DelayedRegistry; ++import io.papermc.paper.registry.legacy.DelayedRegistryEntry; ++import java.util.function.Supplier; ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++ ++public interface RegistryHolder { ++ ++ Registry get(); ++ ++ final class Memoized> implements RegistryHolder { ++ ++ private final Supplier memoizedSupplier; ++ ++ public Memoized(final Supplier supplier) { ++ this.memoizedSupplier = Suppliers.memoize(supplier::get); ++ } ++ ++ public Registry get() { ++ return this.memoizedSupplier.get(); ++ } ++ } ++ ++ final class Delayed> implements RegistryHolder { ++ ++ private final DelayedRegistry delayedRegistry = new DelayedRegistry<>(); ++ ++ @Override ++ public DelayedRegistry get() { ++ return this.delayedRegistry; ++ } ++ ++ void loadFrom(final DelayedRegistryEntry delayedEntry, final net.minecraft.core.Registry registry) { ++ final RegistryHolder delegateHolder = delayedEntry.delegate().createRegistryHolder(registry); ++ if (!(delegateHolder instanceof RegistryHolder.Memoized)) { ++ throw new IllegalArgumentException(delegateHolder + " must be a memoized holder"); ++ } ++ this.delayedRegistry.load(((Memoized) delegateHolder).memoizedSupplier); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/ApiRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/ApiRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2295b0d145cbaabef5d29482c817575dcbe2ba54 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/ApiRegistryEntry.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.RegistryHolder; ++import io.papermc.paper.registry.RegistryKey; ++import java.util.function.Supplier; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++ ++public class ApiRegistryEntry extends BaseRegistryEntry { ++ ++ private final Supplier> registrySupplier; ++ ++ protected ApiRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Supplier> registrySupplier ++ ) { ++ super(mcKey, apiKey); ++ this.registrySupplier = registrySupplier; ++ } ++ ++ @Override ++ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { ++ return new RegistryHolder.Memoized<>(this.registrySupplier); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ceb217dbbb84e8bd51365dd47bf91971e364d298 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.RegistryKey; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++ ++public abstract class BaseRegistryEntry implements RegistryEntry { // TODO remove Keyed ++ ++ private final ResourceKey> minecraftRegistryKey; ++ private final RegistryKey apiRegistryKey; ++ ++ protected BaseRegistryEntry(final ResourceKey> minecraftRegistryKey, final RegistryKey apiRegistryKey) { ++ this.minecraftRegistryKey = minecraftRegistryKey; ++ this.apiRegistryKey = apiRegistryKey; ++ } ++ ++ @Override ++ public final ResourceKey> mcKey() { ++ return this.minecraftRegistryKey; ++ } ++ ++ @Override ++ public final RegistryKey apiKey() { ++ return this.apiRegistryKey; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..45cbc425da64f0bd3290600869ad425d9e6e912b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java +@@ -0,0 +1,48 @@ ++package io.papermc.paper.registry.entry; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.registry.RegistryHolder; ++import io.papermc.paper.registry.RegistryKey; ++import java.util.function.BiFunction; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.CraftRegistry; ++import org.bukkit.craftbukkit.util.ApiVersion; ++ ++public class CraftRegistryEntry extends BaseRegistryEntry { // TODO remove Keyed ++ ++ private static final BiFunction EMPTY = (namespacedKey, apiVersion) -> namespacedKey; ++ ++ protected final Class classToPreload; ++ protected final BiFunction minecraftToBukkit; ++ protected BiFunction updater = EMPTY; ++ ++ protected CraftRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class classToPreload, ++ final BiFunction minecraftToBukkit ++ ) { ++ super(mcKey, apiKey); ++ Preconditions.checkArgument(!classToPreload.getPackageName().startsWith("net.minecraft"), classToPreload + " should not be in the net.minecraft package as the class-to-preload"); ++ this.classToPreload = classToPreload; ++ this.minecraftToBukkit = minecraftToBukkit; ++ } ++ ++ @Override ++ public RegistryEntry withSerializationUpdater(final BiFunction updater) { ++ this.updater = updater; ++ return this; ++ } ++ ++ @Override ++ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { ++ return new RegistryHolder.Memoized<>(() -> this.createApiRegistry(nmsRegistry)); ++ } ++ ++ private CraftRegistry createApiRegistry(final Registry nmsRegistry) { ++ return new CraftRegistry<>(this.classToPreload, nmsRegistry, this.minecraftToBukkit, this.updater); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2889d87f0989ae5744cd4c1e57240830aa574155 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +@@ -0,0 +1,48 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.RegistryHolder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.legacy.DelayedRegistryEntry; ++import java.util.function.BiFunction; ++import java.util.function.Supplier; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.ApiVersion; ++ ++public interface RegistryEntry extends RegistryEntryInfo { // TODO remove Keyed ++ ++ RegistryHolder createRegistryHolder(Registry nmsRegistry); ++ ++ default RegistryEntry withSerializationUpdater(final BiFunction updater) { ++ return this; ++ } ++ ++ /** ++ * This should only be used if the registry instance needs to exist early due to the need ++ * to populate a field in {@link org.bukkit.Registry}. Data-driven registries shouldn't exist ++ * as fields, but instead be obtained via {@link io.papermc.paper.registry.RegistryAccess#getRegistry(RegistryKey)} ++ */ ++ @Deprecated ++ default RegistryEntry delayed() { ++ return new DelayedRegistryEntry<>(this); ++ } ++ ++ static RegistryEntry entry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class classToPreload, ++ final BiFunction minecraftToBukkit ++ ) { ++ return new CraftRegistryEntry<>(mcKey, apiKey, classToPreload, minecraftToBukkit); ++ } ++ ++ static RegistryEntry apiOnly( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Supplier> apiRegistrySupplier ++ ) { ++ return new ApiRegistryEntry<>(mcKey, apiKey, apiRegistrySupplier); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0ae855e80fc9fddfc1feb33c7a9748204828b7cc +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.RegistryKey; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++ ++public interface RegistryEntryInfo { ++ ++ ResourceKey> mcKey(); ++ ++ RegistryKey apiKey(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/package-info.java b/src/main/java/io/papermc/paper/registry/entry/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f04e93aa5ca41ce1cf3b152f827911fdf0dd10cb +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/package-info.java +@@ -0,0 +1,4 @@ ++@NullMarked ++package io.papermc.paper.registry.entry; ++ ++import org.jspecify.annotations.NullMarked; +diff --git a/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ca829b162d4369f845e59b62bb8779fd83fe2ef3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java +@@ -0,0 +1,57 @@ ++package io.papermc.paper.registry.legacy; ++ ++import java.util.Iterator; ++import java.util.function.Supplier; ++import java.util.stream.Stream; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.jspecify.annotations.Nullable; ++ ++/** ++ * This is to support the now-deprecated fields in {@link Registry} for ++ * data-driven registries. ++ */ ++public final class DelayedRegistry> implements Registry { ++ ++ private @Nullable Supplier delegate; ++ ++ public void load(final Supplier registry) { ++ if (this.delegate != null) { ++ throw new IllegalStateException("Registry already loaded!"); ++ } ++ this.delegate = registry; ++ } ++ ++ public Registry delegate() { ++ if (this.delegate == null) { ++ throw new IllegalStateException("You are trying to access this registry too early!"); ++ } ++ return this.delegate.get(); ++ } ++ ++ @Override ++ public @Nullable T get(final NamespacedKey key) { ++ return this.delegate().get(key); ++ } ++ ++ @Override ++ public T getOrThrow(final NamespacedKey key) { ++ return this.delegate().getOrThrow(key); ++ } ++ ++ @Override ++ public Iterator iterator() { ++ return this.delegate().iterator(); ++ } ++ ++ @Override ++ public Stream stream() { ++ return this.delegate().stream(); ++ } ++ ++ @Override ++ public @Nullable NamespacedKey getKey(final T value) { ++ return this.delegate().getKey(value); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..110b8d559f49f9e4f181b47663962a139a273a72 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.registry.legacy; ++ ++import io.papermc.paper.registry.RegistryHolder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.entry.RegistryEntry; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++ ++public record DelayedRegistryEntry(RegistryEntry delegate) implements RegistryEntry { ++ ++ @Override ++ public ResourceKey> mcKey() { ++ return this.delegate.mcKey(); ++ } ++ ++ @Override ++ public RegistryKey apiKey() { ++ return this.delegate.apiKey(); ++ } ++ ++ @Override ++ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { ++ return this.delegate.createRegistryHolder(nmsRegistry); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java +new file mode 100644 +index 0000000000000000000000000000000000000000..83870816cd4c54f94a3c603ffe41c11e457f3dec +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.registry.legacy; ++ ++import com.google.common.collect.ImmutableMap; ++import io.leangen.geantyref.GenericTypeReflector; ++import io.papermc.paper.registry.RegistryKey; ++import java.lang.reflect.Field; ++import java.lang.reflect.ParameterizedType; ++import java.util.Map; ++ ++@Deprecated ++public final class LegacyRegistryIdentifiers { ++ ++ public static final Map, RegistryKey> CLASS_TO_KEY_MAP; ++ ++ static { ++ final ImmutableMap.Builder, RegistryKey> builder = ImmutableMap.builder(); ++ try { ++ for (final Field field : RegistryKey.class.getFields()) { ++ if (field.getType() == RegistryKey.class) { ++ // get the legacy type from the RegistryKey generic parameter on the field ++ final Class legacyType = GenericTypeReflector.erase(((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]); ++ builder.put(legacyType, (RegistryKey) field.get(null)); ++ } ++ } ++ } catch (final ReflectiveOperationException ex) { ++ throw new RuntimeException(ex); ++ } ++ CLASS_TO_KEY_MAP = builder.build(); ++ } ++ ++ private LegacyRegistryIdentifiers() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/package-info.java b/src/main/java/io/papermc/paper/registry/legacy/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..063a8d7a7313d5d685d51df54d9502d72266da49 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/package-info.java +@@ -0,0 +1,4 @@ ++@NullMarked ++package io.papermc.paper.registry.legacy; ++ ++import org.jspecify.annotations.NullMarked; +diff --git a/src/main/java/io/papermc/paper/registry/package-info.java b/src/main/java/io/papermc/paper/registry/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ca07ef31161e938d48214992b34cafb712a51513 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/package-info.java +@@ -0,0 +1,4 @@ ++@NullMarked ++package io.papermc.paper.registry; ++ ++import org.jspecify.annotations.NullMarked; +diff --git a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +index 3f72e30b57fb2a4231e22a2234729408c1240af4..4638ba98dbbdb0f880337347be85a6e0fbed2191 100644 +--- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java ++++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +@@ -323,6 +323,7 @@ public class BuiltInRegistries { + ResourceKey> key, R registry, BuiltInRegistries.RegistryBootstrap initializer + ) { + Bootstrap.checkBootstrapCalled(() -> "registry " + key.location()); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(registry.key(), registry); // Paper - initialize API registry + ResourceLocation resourceLocation = key.location(); + LOADERS.put(resourceLocation, () -> initializer.run(registry)); + WRITABLE_REGISTRY.register((ResourceKey)key, registry, RegistrationInfo.BUILT_IN); // Paper - decompile fix +diff --git a/src/main/java/net/minecraft/resources/RegistryDataLoader.java b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +index b9b9ec93442423e99def9b2c51aedc955a7799d5..b8c1840eeda982c0c6350e49fae2784a599ef3ce 100644 +--- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java ++++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +@@ -349,6 +349,7 @@ public class RegistryDataLoader { + + RegistryDataLoader.Loader create(Lifecycle lifecycle, Map, Exception> errors) { + WritableRegistry writableRegistry = new MappedRegistry<>(this.key, lifecycle); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(this.key, writableRegistry); // Paper - initialize API registry + return new RegistryDataLoader.Loader<>(this, writableRegistry, errors); + } + +diff --git a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java +index 257cfce009fb6fcd24d1fddfd8001e9b2a8ae1ae..185752185549ebd5f431932b63d8e5fea50a2cb2 100644 +--- a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java ++++ b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java +@@ -64,6 +64,7 @@ public class ReloadableServerRegistries { + ) { + return CompletableFuture.supplyAsync(() -> { + WritableRegistry writableRegistry = new MappedRegistry<>(type.registryKey(), Lifecycle.experimental()); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerReloadableRegistry(type.registryKey(), writableRegistry); // Paper - register reloadable registry + Map map = new HashMap<>(); + SimpleJsonResourceReloadListener.scanDirectory(resourceManager, type.registryKey(), ops, type.codec(), map); + map.forEach((id, value) -> writableRegistry.register(ResourceKey.create(type.registryKey(), id), (T)value, DEFAULT_REGISTRATION_INFO)); +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +index 0d091c7b328fb70a82f5b5ded7dec61b7cd3d59a..249f0dcad04a35244da6dab837a461bb42aad00a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -127,96 +127,12 @@ public class CraftRegistry implements Registry { + + ", this can happen if a plugin creates its own registry entry with out properly registering it."); + } + +- /** +- * Note: Newly added registries should also be added to RegistriesArgumentProvider in the test package +- * +- * @param bukkitClass the bukkit class of the registry +- * @param registryHolder the minecraft registry holder +- * @return the bukkit registry of the provided class +- */ +- public static Registry createRegistry(Class bukkitClass, RegistryAccess registryHolder) { +- if (bukkitClass == Art.class) { +- return new CraftRegistry<>(Art.class, registryHolder.lookupOrThrow(Registries.PAINTING_VARIANT), CraftArt::new, FieldRename.NONE); +- } +- if (bukkitClass == Attribute.class) { +- return new CraftRegistry<>(Attribute.class, registryHolder.lookupOrThrow(Registries.ATTRIBUTE), CraftAttribute::new, FieldRename.ATTRIBUTE_RENAME); +- } +- if (bukkitClass == Biome.class) { +- return new CraftRegistry<>(Biome.class, registryHolder.lookupOrThrow(Registries.BIOME), CraftBiome::new, FieldRename.BIOME_RENAME); +- } +- if (bukkitClass == Enchantment.class) { +- return new CraftRegistry<>(Enchantment.class, registryHolder.lookupOrThrow(Registries.ENCHANTMENT), CraftEnchantment::new, FieldRename.ENCHANTMENT_RENAME); +- } +- if (bukkitClass == Fluid.class) { +- return new CraftRegistry<>(Fluid.class, registryHolder.lookupOrThrow(Registries.FLUID), CraftFluid::new, FieldRename.NONE); +- } +- if (bukkitClass == GameEvent.class) { +- return new CraftRegistry<>(GameEvent.class, registryHolder.lookupOrThrow(Registries.GAME_EVENT), CraftGameEvent::new, FieldRename.NONE); +- } +- if (bukkitClass == MusicInstrument.class) { +- return new CraftRegistry<>(MusicInstrument.class, registryHolder.lookupOrThrow(Registries.INSTRUMENT), CraftMusicInstrument::new, FieldRename.NONE); +- } +- if (bukkitClass == MenuType.class) { +- return new CraftRegistry<>(MenuType.class, registryHolder.lookupOrThrow(Registries.MENU), CraftMenuType::new, FieldRename.NONE); +- } +- if (bukkitClass == PotionEffectType.class) { +- return new CraftRegistry<>(PotionEffectType.class, registryHolder.lookupOrThrow(Registries.MOB_EFFECT), CraftPotionEffectType::new, FieldRename.NONE); +- } +- if (bukkitClass == Sound.class) { +- return new CraftRegistry<>(Sound.class, registryHolder.lookupOrThrow(Registries.SOUND_EVENT), CraftSound::new, FieldRename.NONE); +- } +- if (bukkitClass == Structure.class) { +- return new CraftRegistry<>(Structure.class, registryHolder.lookupOrThrow(Registries.STRUCTURE), CraftStructure::new, FieldRename.NONE); +- } +- if (bukkitClass == StructureType.class) { +- return new CraftRegistry<>(StructureType.class, registryHolder.lookupOrThrow(Registries.STRUCTURE_TYPE), CraftStructureType::new, FieldRename.NONE); +- } +- if (bukkitClass == Villager.Type.class) { +- return new CraftRegistry<>(Villager.Type.class, registryHolder.lookupOrThrow(Registries.VILLAGER_TYPE), CraftVillager.CraftType::new, FieldRename.NONE); +- } +- if (bukkitClass == Villager.Profession.class) { +- return new CraftRegistry<>(Villager.Profession.class, registryHolder.lookupOrThrow(Registries.VILLAGER_PROFESSION), CraftVillager.CraftProfession::new, FieldRename.NONE); +- } +- if (bukkitClass == TrimMaterial.class) { +- return new CraftRegistry<>(TrimMaterial.class, registryHolder.lookupOrThrow(Registries.TRIM_MATERIAL), CraftTrimMaterial::new, FieldRename.NONE); +- } +- if (bukkitClass == TrimPattern.class) { +- return new CraftRegistry<>(TrimPattern.class, registryHolder.lookupOrThrow(Registries.TRIM_PATTERN), CraftTrimPattern::new, FieldRename.NONE); +- } +- if (bukkitClass == DamageType.class) { +- return new CraftRegistry<>(DamageType.class, registryHolder.lookupOrThrow(Registries.DAMAGE_TYPE), CraftDamageType::new, FieldRename.NONE); +- } +- if (bukkitClass == JukeboxSong.class) { +- return new CraftRegistry<>(JukeboxSong.class, registryHolder.lookupOrThrow(Registries.JUKEBOX_SONG), CraftJukeboxSong::new, FieldRename.NONE); +- } +- if (bukkitClass == Wolf.Variant.class) { +- return new CraftRegistry<>(Wolf.Variant.class, registryHolder.lookupOrThrow(Registries.WOLF_VARIANT), CraftWolf.CraftVariant::new, FieldRename.NONE); +- } +- if (bukkitClass == BlockType.class) { +- return new CraftRegistry<>(BlockType.class, registryHolder.lookupOrThrow(Registries.BLOCK), CraftBlockType::new, FieldRename.NONE); +- } +- if (bukkitClass == ItemType.class) { +- return new CraftRegistry<>(ItemType.class, registryHolder.lookupOrThrow(Registries.ITEM), CraftItemType::new, FieldRename.NONE); +- } +- if (bukkitClass == Frog.Variant.class) { +- return new CraftRegistry<>(Frog.Variant.class, registryHolder.lookupOrThrow(Registries.FROG_VARIANT), CraftFrog.CraftVariant::new, FieldRename.NONE); +- } +- if (bukkitClass == Cat.Type.class) { +- return new CraftRegistry<>(Cat.Type.class, registryHolder.lookupOrThrow(Registries.CAT_VARIANT), CraftCat.CraftType::new, FieldRename.NONE); +- } +- if (bukkitClass == MapCursor.Type.class) { +- return new CraftRegistry<>(MapCursor.Type.class, registryHolder.lookupOrThrow(Registries.MAP_DECORATION_TYPE), CraftMapCursor.CraftType::new, FieldRename.NONE); +- } +- if (bukkitClass == PatternType.class) { +- return new CraftRegistry<>(PatternType.class, registryHolder.lookupOrThrow(Registries.BANNER_PATTERN), CraftPatternType::new, FieldRename.NONE); +- } +- +- return null; +- } ++ // Paper - move to PaperRegistries + ++ // Paper - NOTE: As long as all uses of the method below relate to *serialization* via ConfigurationSerializable, it's fine + public static B get(Registry bukkit, NamespacedKey namespacedKey, ApiVersion apiVersion) { + if (bukkit instanceof CraftRegistry craft) { +- return craft.get(namespacedKey, apiVersion); ++ return craft.get(craft.serializationUpdater.apply(namespacedKey, apiVersion)); // Paper + } + + if (bukkit instanceof Registry.SimpleRegistry simple) { +@@ -234,23 +150,21 @@ public class CraftRegistry implements Registry { + return bukkit.get(namespacedKey); + } + +- private final Class bukkitClass; ++ private final Class bukkitClass; // Paper - relax preload class + private final Map cache = new HashMap<>(); + private final net.minecraft.core.Registry minecraftRegistry; + private final BiFunction minecraftToBukkit; +- private final BiFunction updater; ++ private final BiFunction serializationUpdater; // Paper - rename to make it *clear* what it is *only* for + private boolean init; + +- public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit, BiFunction updater) { ++ public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit, BiFunction serializationUpdater) { // Paper - relax preload class + this.bukkitClass = bukkitClass; + this.minecraftRegistry = minecraftRegistry; + this.minecraftToBukkit = minecraftToBukkit; +- this.updater = updater; ++ this.serializationUpdater = serializationUpdater; + } + +- public B get(NamespacedKey namespacedKey, ApiVersion apiVersion) { +- return this.get(this.updater.apply(namespacedKey, apiVersion)); +- } ++ // Paper - inline into CraftRegistry#get(Registry, NamespacedKey, ApiVersion) above + + @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 f75d73402cf633254fe1ef4e919f09db48165190..5ae8f646083fb580ac8d28fcbfe8ed2208b45d09 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 { + protected final DedicatedServer console; + protected final DedicatedPlayerList playerList; + private final Map worlds = new LinkedHashMap(); +- private final Map, Registry> registries = new HashMap<>(); ++ // private final Map, Registry> registries = new HashMap<>(); // Paper - replace with RegistryAccess + private YamlConfiguration configuration; + private YamlConfiguration commandsConfiguration; + private final Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); +@@ -431,6 +431,7 @@ public final class CraftServer implements Server { + } + + private void loadCompatibilities() { ++ if (true) return; // Paper - Big nope + ConfigurationSection compatibilities = this.configuration.getConfigurationSection("settings.compatibility"); + if (compatibilities == null) { + this.activeCompatibilities = Collections.emptySet(); +@@ -2754,7 +2755,7 @@ public final class CraftServer implements Server { + + @Override + public Registry getRegistry(Class aClass) { +- return (Registry) this.registries.computeIfAbsent(aClass, key -> CraftRegistry.createRegistry(aClass, this.console.registryAccess())); ++ return io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(aClass); // Paper - replace with RegistryAccess + } + + @Deprecated +diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java b/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java +index 091e11934bddb180f0b2e51efb3921c62275d41d..12fe2f8d0dcb715545e071023490a32125b9c4a4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java ++++ b/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java +@@ -51,11 +51,14 @@ public class FieldRename { + }; + } + +- @RequireCompatibility("allow-old-keys-in-registry") +- public static T get(Registry registry, NamespacedKey namespacedKey) { +- // We don't have version-specific changes, so just use current, and don't inject a version +- return CraftRegistry.get(registry, namespacedKey, ApiVersion.CURRENT); +- } ++ // Paper start - absolutely not, having this as an expectation for plugin developers opens a huge ++ // can of worms in the future, especially if mojang comes back and reuses some old key ++ //@RequireCompatibility("allow-old-keys-in-registry") ++ //public static T get(Registry registry, NamespacedKey namespacedKey) { ++ // // We don't have version-specific changes, so just use current, and don't inject a version ++ // return CraftRegistry.get(registry, namespacedKey, ApiVersion.CURRENT); ++ //} ++ // Paper end + + // PatternType + private static final FieldRenameData PATTERN_TYPE_DATA = FieldRenameData.Builder.newBuilder() +diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +index 61d617d4abb9c9cf5c711459aa98c8b173597a9a..c9b789c2a904c2caff516ee9aeff4a6b368766f4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +@@ -220,20 +220,10 @@ public class Commodore { + + public byte[] convert(byte[] b, final String pluginName, final ApiVersion pluginVersion, final Set activeCompatibilities) { + final boolean modern = pluginVersion.isNewerThanOrSameAs(ApiVersion.FLATTENING); +- final boolean enumCompatibility = pluginVersion.isOlderThanOrSameAs(ApiVersion.getOrCreateVersion("1.20.6")) && activeCompatibilities.contains("enum-compatibility-mode"); + ClassReader cr = new ClassReader(b); + ClassWriter cw = new ClassWriter(cr, 0); + +- List methodEnumSignatures = Commodore.getMethodSignatures(b); +- Multimap enumLessToEnum = HashMultimap.create(); +- for (String method : methodEnumSignatures) { +- enumLessToEnum.put(method.replace("Ljava/lang/Enum;", "Ljava/lang/Object;"), method); +- } +- + ClassVisitor visitor = cw; +- if (enumCompatibility) { +- visitor = new LimitedClassRemapper(cw, new SimpleRemapper(Commodore.ENUM_RENAMES)); +- } + + visitor = io.papermc.paper.pluginremap.reflect.ReflectionRemapper.visitor(visitor); // Paper + cr.accept(new ClassRemapper(new ClassVisitor(Opcodes.ASM9, visitor) { +@@ -300,15 +290,6 @@ public class Commodore { + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { +- if (enumCompatibility && (access & Opcodes.ACC_SYNTHETIC) != 0 && (access & Opcodes.ACC_BRIDGE) != 0 && desc.contains("Ljava/lang/Object;")) { +- // SPIGOT-7820: Do not use object method if enum method is present +- // The object method does only redirect to the enum method +- Collection result = enumLessToEnum.get(desc.replace("Ljava/lang/Enum;", "Ljava/lang/Object;") + " " + name); +- if (result.size() == 2) { +- name = name + "_BUKKIT_UNUSED"; +- } +- } +- + return new MethodVisitor(this.api, super.visitMethod(access, name, desc, signature, exceptions)) { + // Paper start - Plugin rewrites + @Override +diff --git a/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess b/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +new file mode 100644 +index 0000000000000000000000000000000000000000..8a083d45004f82fc9c51c219fb20f34624adb501 +--- /dev/null ++++ b/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +@@ -0,0 +1 @@ ++io.papermc.paper.registry.PaperRegistryAccess +diff --git a/src/main/resources/configurations/bukkit.yml b/src/main/resources/configurations/bukkit.yml +index 543e37737bc6fdca23ed9ed0606805d345515a5a..eef7c125b2689f29cae5464659eacdf33f5695b2 100644 +--- a/src/main/resources/configurations/bukkit.yml ++++ b/src/main/resources/configurations/bukkit.yml +@@ -23,9 +23,6 @@ settings: + shutdown-message: Server closed + minimum-api: none + use-map-color-cache: true +- compatibility: +- allow-old-keys-in-registry: false +- enum-compatibility-mode: false + spawn-limits: + monsters: 70 + animals: 10 +diff --git a/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a80b0ded74c0be657e734de61cbf5e32e16c26a8 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java +@@ -0,0 +1,21 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.GameEvent; ++import org.bukkit.MusicInstrument; ++import org.bukkit.inventory.meta.trim.TrimPattern; ++import org.bukkit.support.environment.VanillaFeature; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertSame; ++ ++@Deprecated ++@VanillaFeature ++class LegacyRegistryIdentifierTest { ++ ++ @Test ++ void testSeveralConversions() { ++ assertSame(RegistryKey.GAME_EVENT, PaperRegistryAccess.byType(GameEvent.class)); ++ assertSame(RegistryKey.TRIM_PATTERN, PaperRegistryAccess.byType(TrimPattern.class)); ++ assertSame(RegistryKey.INSTRUMENT, PaperRegistryAccess.byType(MusicInstrument.class)); ++ } ++} +diff --git a/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java +index d8857a05858585113bc7efde3416748effb53d01..41c38b1b6d25c7a7ed08d70b19f5f4a70fc2df94 100644 +--- a/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java ++++ b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java +@@ -1,15 +1,19 @@ + package io.papermc.paper.registry; + ++import io.papermc.paper.registry.entry.RegistryEntry; + import java.util.Optional; + import java.util.stream.Stream; + import net.minecraft.core.Registry; + import net.minecraft.resources.ResourceKey; + import net.minecraft.resources.ResourceLocation; +-import org.bukkit.support.AbstractTestingBase; ++import org.bukkit.support.RegistryHelper; ++import org.bukkit.support.environment.AllFeatures; ++import org.checkerframework.checker.nullness.qual.Nullable; + import org.junit.jupiter.api.BeforeAll; + import org.junit.jupiter.params.ParameterizedTest; + import org.junit.jupiter.params.provider.MethodSource; + ++import static org.junit.jupiter.api.Assertions.assertNotNull; + import static org.junit.jupiter.api.Assertions.assertTrue; + + @AllFeatures +@@ -29,6 +33,12 @@ class RegistryKeyTest { + void testApiRegistryKeysExist(final RegistryKey key) { + final Optional> registry = RegistryHelper.getRegistry().lookup(ResourceKey.createRegistryKey(ResourceLocation.parse(key.key().asString()))); + assertTrue(registry.isPresent(), "Missing vanilla registry for " + key.key().asString()); ++ } + ++ @ParameterizedTest ++ @MethodSource("data") ++ void testRegistryEntryExists(final RegistryKey key) { ++ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(key); ++ assertNotNull(entry, "Missing PaperRegistries entry for " + key); + } + } +diff --git a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java +index b65a3ee68c177da7ef5a57608187dc1672257c7f..c1016e0eb00e952551370c874e8d678fef8ba3dc 100644 +--- a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java ++++ b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java +@@ -22,14 +22,17 @@ public class RegistryArgumentAddedTest { + // Make sure every registry is created + Class.forName(Registry.class.getName()); + +- Set> loadedRegistries = new HashSet<>(AllFeaturesExtension.getRealRegistries().keySet()); +- Set> notFound = new HashSet<>(); ++ // Paper start ++ Set> loadedRegistries = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap<>()); ++ loadedRegistries.addAll(io.papermc.paper.registry.PaperRegistryAccess.instance().getLoadedServerBackedRegistries()); ++ // Paper end ++ Set> notFound = new HashSet<>(); // Paper + + RegistriesArgumentProvider + .getData() + .map(Arguments::get) + .map(array -> array[0]) +- .map(clazz -> (Class) clazz) ++ .map(clazz -> (io.papermc.paper.registry.RegistryKey) clazz) // Paper + .forEach(clazz -> { + if (!loadedRegistries.remove(clazz)) { + notFound.add(clazz); +diff --git a/src/test/java/org/bukkit/registry/RegistryConversionTest.java b/src/test/java/org/bukkit/registry/RegistryConversionTest.java +index e97328b95973db52d44bc4d0aefd8eb69f2ebdea..01e351f4e292efe78fc1a1db0f31b2c0a313b101 100644 +--- a/src/test/java/org/bukkit/registry/RegistryConversionTest.java ++++ b/src/test/java/org/bukkit/registry/RegistryConversionTest.java +@@ -41,9 +41,9 @@ public class RegistryConversionTest { + + @Order(1) + @RegistriesTest +- public void testHandleableImplementation(Class clazz) { ++ public void testHandleableImplementation(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper + Set> notImplemented = new HashSet<>(); +- Registry registry = Bukkit.getRegistry(clazz); ++ Registry registry = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(type); // Paper + + for (Keyed item : registry) { + if (!(item instanceof Handleable)) { +@@ -63,7 +63,7 @@ public class RegistryConversionTest { + + @Order(2) + @RegistriesTest +- public void testMinecraftToBukkitPresent(Class clazz, ResourceKey> registryKey, ++ public void testMinecraftToBukkitPresent(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, + Class craftClazz, Class minecraftClazz, boolean newMethod) { + String methodName = (newMethod) ? RegistryConversionTest.MINECRAFT_TO_BUKKIT_NEW : RegistryConversionTest.MINECRAFT_TO_BUKKIT; + Method method = null; +@@ -112,7 +112,7 @@ public class RegistryConversionTest { + + @Order(2) + @RegistriesTest +- public void testBukkitToMinecraftPresent(Class clazz, ResourceKey> registryKey, ++ public void testBukkitToMinecraftPresent(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, + Class craftClazz, Class minecraftClazz, boolean newMethod) { + String methodName = (newMethod) ? RegistryConversionTest.BUKKIT_TO_MINECRAFT_NEW : RegistryConversionTest.BUKKIT_TO_MINECRAFT; + Method method = null; +@@ -159,9 +159,9 @@ public class RegistryConversionTest { + """, minecraftClazz.getName(), methodName, clazz.getSimpleName()); + } + +- @Order(2) ++ @Order(3) + @RegistriesTest +- public void testMinecraftToBukkitNullValue(Class clazz) throws IllegalAccessException { ++ public void testMinecraftToBukkitNullValue(io.papermc.paper.registry.RegistryKey type, Class clazz) throws IllegalAccessException { // Paper + this.checkValidMinecraftToBukkit(clazz); + + try { +@@ -180,7 +180,7 @@ public class RegistryConversionTest { + + @Order(3) + @RegistriesTest +- public void testBukkitToMinecraftNullValue(Class clazz) throws IllegalAccessException { ++ public void testBukkitToMinecraftNullValue(io.papermc.paper.registry.RegistryKey type, Class clazz) throws IllegalAccessException { // Paper + this.checkValidBukkitToMinecraft(clazz); + + try { +@@ -199,14 +199,14 @@ public class RegistryConversionTest { + + @Order(3) + @RegistriesTest +- public void testMinecraftToBukkit(Class clazz) { ++ public void testMinecraftToBukkit(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper + this.checkValidMinecraftToBukkit(clazz); + this.checkValidHandle(clazz); + + Map notMatching = new HashMap<>(); + Method method = RegistryConversionTest.MINECRAFT_TO_BUKKIT_METHODS.get(clazz); + +- RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> { ++ RegistryArgumentProvider.getValues(type).map(Arguments::get).forEach(arguments -> { // Paper + Keyed bukkit = (Keyed) arguments[0]; + Object minecraft = arguments[1]; + +@@ -230,14 +230,14 @@ public class RegistryConversionTest { + + @Order(3) + @RegistriesTest +- public void testBukkitToMinecraft(Class clazz) { ++ public void testBukkitToMinecraft(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper + this.checkValidBukkitToMinecraft(clazz); + this.checkValidHandle(clazz); + + Map notMatching = new HashMap<>(); + Method method = RegistryConversionTest.BUKKIT_TO_MINECRAFT_METHODS.get(clazz); + +- RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> { ++ RegistryArgumentProvider.getValues(type).map(Arguments::get).forEach(arguments -> { // Paper + Keyed bukkit = (Keyed) arguments[0]; + Object minecraft = arguments[1]; + +@@ -265,7 +265,7 @@ public class RegistryConversionTest { + */ + @Order(3) + @RegistriesTest +- public void testMinecraftToBukkitNoValidMinecraft(Class clazz, ResourceKey> registryKey, ++ public void testMinecraftToBukkitNoValidMinecraft(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, // Paper + Class craftClazz, Class minecraftClazz) throws IllegalAccessException { + this.checkValidMinecraftToBukkit(clazz); + +diff --git a/src/test/java/org/bukkit/support/extension/AllFeaturesExtension.java b/src/test/java/org/bukkit/support/extension/AllFeaturesExtension.java +index e9eb521419bbacb03d7000ace355f2a9f5a6a9c5..8fef8421e3cf87913746a314a477634bd3e99300 100644 +--- a/src/test/java/org/bukkit/support/extension/AllFeaturesExtension.java ++++ b/src/test/java/org/bukkit/support/extension/AllFeaturesExtension.java +@@ -39,22 +39,7 @@ public class AllFeaturesExtension extends BaseExtension { + + Bukkit.setServer(server); + +- when(server.getRegistry(any())) +- .then(invocation -> { +- Class keyed = invocation.getArgument(0); +- if (spyRegistries.containsKey(keyed)) { +- return spyRegistries.get(keyed); +- } +- +- Registry registry = CraftRegistry.createRegistry(keyed, RegistryHelper.getRegistry()); +- realRegistries.put(keyed, registry); +- +- Registry spy = mock(registry.getClass(), withSettings().stubOnly().spiedInstance(registry).defaultAnswer(CALLS_REAL_METHODS)); +- +- spyRegistries.put(keyed, spy); +- +- return spy; +- }); ++ // Paper - Add RegistryAccess for managing registries - replaced with registry access + + CraftRegistry.setMinecraftRegistry(RegistryHelper.getRegistry()); + } +diff --git a/src/test/java/org/bukkit/support/extension/LegacyExtension.java b/src/test/java/org/bukkit/support/extension/LegacyExtension.java +index 94cf52cf7603e6814682c92b26fcf03a8b927838..c9c3227c3b7fa36ed80f2dc828885a0128e1e3d0 100644 +--- a/src/test/java/org/bukkit/support/extension/LegacyExtension.java ++++ b/src/test/java/org/bukkit/support/extension/LegacyExtension.java +@@ -30,11 +30,7 @@ public class LegacyExtension extends BaseExtension { + + Bukkit.setServer(server); + +- when(server.getRegistry(any())) +- .then(invocation -> { +- Class keyed = invocation.getArgument(0); +- return registries.computeIfAbsent(keyed, k -> CraftRegistry.createRegistry(keyed, RegistryHelper.getRegistry())); +- }); ++ // Paper - Add RegistryAccess for managing registries - replaced with registry access + + CraftRegistry.setMinecraftRegistry(RegistryHelper.getRegistry()); + } +diff --git a/src/test/java/org/bukkit/support/extension/SlowExtension.java b/src/test/java/org/bukkit/support/extension/SlowExtension.java +index e0ce6836d4365c36303f6c675a75ef6a9b047b92..87364f223fbd6185b041138550fcb6e3ed07d1ae 100644 +--- a/src/test/java/org/bukkit/support/extension/SlowExtension.java ++++ b/src/test/java/org/bukkit/support/extension/SlowExtension.java +@@ -30,11 +30,7 @@ public class SlowExtension extends BaseExtension { + + Bukkit.setServer(server); + +- when(server.getRegistry(any())) +- .then(invocation -> { +- Class keyed = invocation.getArgument(0); +- return registries.computeIfAbsent(keyed, k -> CraftRegistry.createRegistry(keyed, RegistryHelper.getRegistry())); +- }); ++ // Paper - Add RegistryAccess for managing registries - replaced with registry access + + CraftRegistry.setMinecraftRegistry(RegistryHelper.getRegistry()); + } +diff --git a/src/test/java/org/bukkit/support/extension/VanillaFeatureExtension.java b/src/test/java/org/bukkit/support/extension/VanillaFeatureExtension.java +index bbd5dd5b27937ddc3d8c57f2b604331495b0f311..626c3033e36897846fe84a77d05e2e91a15598e5 100644 +--- a/src/test/java/org/bukkit/support/extension/VanillaFeatureExtension.java ++++ b/src/test/java/org/bukkit/support/extension/VanillaFeatureExtension.java +@@ -30,11 +30,7 @@ public class VanillaFeatureExtension extends BaseExtension { + + Bukkit.setServer(server); + +- when(server.getRegistry(any())) +- .then(invocation -> { +- Class keyed = invocation.getArgument(0); +- return registries.computeIfAbsent(keyed, k -> CraftRegistry.createRegistry(keyed, RegistryHelper.getRegistry())); +- }); ++ // Paper - Add RegistryAccess for managing registries - replaced with registry access + + CraftRegistry.setMinecraftRegistry(RegistryHelper.getRegistry()); + } +diff --git a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +index bfec6280e8b753a29ad2d9eb88808beb79ec65ea..b717a5ffa567781b0687bbe238b62844214db284 100644 +--- a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java ++++ b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +@@ -1,6 +1,7 @@ + package org.bukkit.support.provider; + + import com.google.common.collect.Lists; ++import io.papermc.paper.registry.RegistryKey; + import java.util.List; + import java.util.stream.Stream; + import net.minecraft.core.registries.Registries; +@@ -73,41 +74,40 @@ public class RegistriesArgumentProvider implements ArgumentsProvider { + private static final List DATA = Lists.newArrayList(); + + static { +- // Order: Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class +- register(Art.class, Registries.PAINTING_VARIANT, CraftArt.class, PaintingVariant.class); +- register(Attribute.class, Registries.ATTRIBUTE, CraftAttribute.class, net.minecraft.world.entity.ai.attributes.Attribute.class); +- register(Biome.class, Registries.BIOME, CraftBiome.class, net.minecraft.world.level.biome.Biome.class); +- register(Enchantment.class, Registries.ENCHANTMENT, CraftEnchantment.class, net.minecraft.world.item.enchantment.Enchantment.class); +- register(Fluid.class, Registries.FLUID, CraftFluid.class, net.minecraft.world.level.material.Fluid.class); +- register(GameEvent.class, Registries.GAME_EVENT, CraftGameEvent.class, net.minecraft.world.level.gameevent.GameEvent.class); +- register(MusicInstrument.class, Registries.INSTRUMENT, CraftMusicInstrument.class, Instrument.class); +- register(MenuType.class, Registries.MENU, CraftMenuType.class, net.minecraft.world.inventory.MenuType.class); +- register(PotionEffectType.class, Registries.MOB_EFFECT, CraftPotionEffectType.class, MobEffect.class); +- register(Sound.class, Registries.SOUND_EVENT, CraftSound.class, SoundEvent.class); +- register(Structure.class, Registries.STRUCTURE, CraftStructure.class, net.minecraft.world.level.levelgen.structure.Structure.class); +- register(StructureType.class, Registries.STRUCTURE_TYPE, CraftStructureType.class, net.minecraft.world.level.levelgen.structure.StructureType.class); +- register(Villager.Type.class, Registries.VILLAGER_TYPE, CraftVillager.CraftType.class, VillagerType.class); +- register(Villager.Profession.class, Registries.VILLAGER_PROFESSION, CraftVillager.CraftProfession.class, VillagerProfession.class); +- register(TrimMaterial.class, Registries.TRIM_MATERIAL, CraftTrimMaterial.class, net.minecraft.world.item.equipment.trim.TrimMaterial.class); +- register(TrimPattern.class, Registries.TRIM_PATTERN, CraftTrimPattern.class, net.minecraft.world.item.equipment.trim.TrimPattern.class); +- register(DamageType.class, Registries.DAMAGE_TYPE, CraftDamageType.class, net.minecraft.world.damagesource.DamageType.class); +- register(JukeboxSong.class, Registries.JUKEBOX_SONG, CraftJukeboxSong.class, net.minecraft.world.item.JukeboxSong.class); +- register(Wolf.Variant.class, Registries.WOLF_VARIANT, CraftWolf.CraftVariant.class, WolfVariant.class); +- register(ItemType.class, Registries.ITEM, CraftItemType.class, net.minecraft.world.item.Item.class, true); +- register(BlockType.class, Registries.BLOCK, CraftBlockType.class, net.minecraft.world.level.block.Block.class, true); +- register(Frog.Variant.class, Registries.FROG_VARIANT, CraftFrog.CraftVariant.class, FrogVariant.class); +- register(Cat.Type.class, Registries.CAT_VARIANT, CraftCat.CraftType.class, CatVariant.class); +- register(MapCursor.Type.class, Registries.MAP_DECORATION_TYPE, CraftMapCursor.CraftType.class, MapDecorationType.class); +- register(PatternType.class, Registries.BANNER_PATTERN, CraftPatternType.class, BannerPattern.class); +- ++ // Order: RegistryKey, Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class ++ register(RegistryKey.PAINTING_VARIANT, Art.class, Registries.PAINTING_VARIANT, CraftArt.class, PaintingVariant.class); ++ register(RegistryKey.ATTRIBUTE, Attribute.class, Registries.ATTRIBUTE, CraftAttribute.class, net.minecraft.world.entity.ai.attributes.Attribute.class); ++ register(RegistryKey.BIOME, Biome.class, Registries.BIOME, CraftBiome.class, net.minecraft.world.level.biome.Biome.class); ++ register(RegistryKey.ENCHANTMENT, Enchantment.class, Registries.ENCHANTMENT, CraftEnchantment.class, net.minecraft.world.item.enchantment.Enchantment.class); ++ register(RegistryKey.FLUID, Fluid.class, Registries.FLUID, CraftFluid.class, net.minecraft.world.level.material.Fluid.class); ++ register(RegistryKey.GAME_EVENT, GameEvent.class, Registries.GAME_EVENT, CraftGameEvent.class, net.minecraft.world.level.gameevent.GameEvent.class); ++ register(RegistryKey.INSTRUMENT, MusicInstrument.class, Registries.INSTRUMENT, CraftMusicInstrument.class, Instrument.class); ++ register(RegistryKey.MOB_EFFECT, PotionEffectType.class, Registries.MOB_EFFECT, CraftPotionEffectType.class, MobEffect.class); ++ register(RegistryKey.SOUND_EVENT, Sound.class, Registries.SOUND_EVENT, CraftSound.class, SoundEvent.class); ++ register(RegistryKey.STRUCTURE, Structure.class, Registries.STRUCTURE, CraftStructure.class, net.minecraft.world.level.levelgen.structure.Structure.class); ++ register(RegistryKey.STRUCTURE_TYPE, StructureType.class, Registries.STRUCTURE_TYPE, CraftStructureType.class, net.minecraft.world.level.levelgen.structure.StructureType.class); ++ register(RegistryKey.VILLAGER_TYPE, Villager.Type.class, Registries.VILLAGER_TYPE, CraftVillager.CraftType.class, VillagerType.class); ++ register(RegistryKey.VILLAGER_PROFESSION, Villager.Profession.class, Registries.VILLAGER_PROFESSION, CraftVillager.CraftProfession.class, VillagerProfession.class); ++ register(RegistryKey.TRIM_MATERIAL, TrimMaterial.class, Registries.TRIM_MATERIAL, CraftTrimMaterial.class, net.minecraft.world.item.equipment.trim.TrimMaterial.class); ++ register(RegistryKey.TRIM_PATTERN, TrimPattern.class, Registries.TRIM_PATTERN, CraftTrimPattern.class, net.minecraft.world.item.equipment.trim.TrimPattern.class); ++ register(RegistryKey.DAMAGE_TYPE, DamageType.class, Registries.DAMAGE_TYPE, CraftDamageType.class, net.minecraft.world.damagesource.DamageType.class); ++ register(RegistryKey.JUKEBOX_SONG, JukeboxSong.class, Registries.JUKEBOX_SONG, CraftJukeboxSong.class, net.minecraft.world.item.JukeboxSong.class); ++ register(RegistryKey.WOLF_VARIANT, Wolf.Variant.class, Registries.WOLF_VARIANT, CraftWolf.CraftVariant.class, WolfVariant.class); ++ register(RegistryKey.ITEM, ItemType.class, Registries.ITEM, CraftItemType.class, net.minecraft.world.item.Item.class, true); ++ register(RegistryKey.BLOCK, BlockType.class, Registries.BLOCK, CraftBlockType.class, net.minecraft.world.level.block.Block.class, true); ++ register(RegistryKey.FROG_VARIANT, Frog.Variant.class, Registries.FROG_VARIANT, CraftFrog.CraftVariant.class, FrogVariant.class); ++ register(RegistryKey.CAT_VARIANT, Cat.Type.class, Registries.CAT_VARIANT, CraftCat.CraftType.class, CatVariant.class); ++ register(RegistryKey.MAP_DECORATION_TYPE, MapCursor.Type.class, Registries.MAP_DECORATION_TYPE, CraftMapCursor.CraftType.class, MapDecorationType.class); ++ register(RegistryKey.BANNER_PATTERN, PatternType.class, Registries.BANNER_PATTERN, CraftPatternType.class, BannerPattern.class); ++ register(RegistryKey.MENU, MenuType.class, Registries.MENU, CraftMenuType.class, net.minecraft.world.inventory.MenuType.class); + } + +- private static void register(Class bukkit, ResourceKey registry, Class craft, Class minecraft) { +- RegistriesArgumentProvider.register(bukkit, registry, craft, minecraft, false); ++ private static void register(RegistryKey registryKey, Class bukkit, ResourceKey registry, Class craft, Class minecraft) { // Paper ++ RegistriesArgumentProvider.register(registryKey, bukkit, registry, craft, minecraft, false); + } + +- private static void register(Class bukkit, ResourceKey registry, Class craft, Class minecraft, boolean newClass) { +- RegistriesArgumentProvider.DATA.add(Arguments.of(bukkit, registry, craft, minecraft, newClass)); ++ private static void register(RegistryKey registryKey, Class bukkit, ResourceKey registry, Class craft, Class minecraft, boolean newClass) { // Paper ++ RegistriesArgumentProvider.DATA.add(Arguments.of(registryKey, bukkit, registry, craft, minecraft, newClass)); + } + + @Override +diff --git a/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java b/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java +index f2ceb5e67536dfa5de792dc64a7898fd2e8aa810..beb5fc9e721f5de54064c3d241df9ca9f4cd4f65 100644 +--- a/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java ++++ b/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java +@@ -22,11 +22,11 @@ public class RegistryArgumentProvider implements ArgumentsProvider, AnnotationCo + + @Override + public Stream provideArguments(ExtensionContext extensionContext) throws Exception { +- return RegistryArgumentProvider.getValues(this.registryType); ++ return RegistryArgumentProvider.getValues(io.papermc.paper.registry.PaperRegistryAccess.byType(this.registryType)); // Paper + } + +- public static Stream getValues(Class registryType) { +- Registry registry = Bukkit.getRegistry(registryType); ++ public static Stream getValues(io.papermc.paper.registry.RegistryKey registryType) { // Paper ++ Registry registry = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(registryType); // Paper + return registry.stream().map(keyed -> (Handleable) keyed) + .map(handleAble -> Arguments.of(handleAble, handleAble.getHandle())); + } diff --git a/patches/server/0463-Add-sendOpLevel-API.patch b/patches/server/0463-Add-sendOpLevel-API.patch deleted file mode 100644 index df8490e384..0000000000 --- a/patches/server/0463-Add-sendOpLevel-API.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Tue, 29 Dec 2020 15:03:03 +0100 -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 4a86a15b009412208247edd7bb8e4655f92da5d1..f023959eee56d8d37cf0a76cb7352c0045cd2ea0 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 { - } - - private void sendPlayerPermissionLevel(ServerPlayer player, int permissionLevel) { -+ // Paper start - Add sendOpLevel API -+ this.sendPlayerPermissionLevel(player, permissionLevel, true); -+ } -+ public void sendPlayerPermissionLevel(ServerPlayer player, int permissionLevel, boolean recalculatePermissions) { -+ // Paper end - Add sendOpLevel API - if (player.connection != null) { - byte b0; - -@@ -1040,8 +1045,10 @@ public abstract class PlayerList { - player.connection.send(new ClientboundEntityEventPacket(player, b0)); - } - -+ if (recalculatePermissions) { // Paper - Add sendOpLevel API - player.getBukkitEntity().recalculatePermissions(); // CraftBukkit - this.server.getCommands().sendCommands(player); -+ } // Paper - Add sendOpLevel API - } - - public boolean isWhiteListed(GameProfile profile) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 0aaea6091c5828782ed606d250423f3d75b9b27f..c93ec7e97c9af44ed75e7ea4fb1c6c58c2b6bc1a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -684,6 +684,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - // Paper end - -+ // Paper start - Add sendOpLevel API -+ @Override -+ public void sendOpLevel(byte level) { -+ Preconditions.checkArgument(level >= 0 && level <= 4, "Level must be within [0, 4]"); -+ -+ this.getHandle().getServer().getPlayerList().sendPlayerPermissionLevel(this.getHandle(), level, false); -+ } -+ // Paper end - Add sendOpLevel API -+ - @Override - public void setCompassTarget(Location loc) { - Preconditions.checkArgument(loc != null, "Location cannot be null"); diff --git a/patches/server/0464-Add-RegistryAccess-for-managing-Registries.patch b/patches/server/0464-Add-RegistryAccess-for-managing-Registries.patch deleted file mode 100644 index 9c82b85992..0000000000 --- a/patches/server/0464-Add-RegistryAccess-for-managing-Registries.patch +++ /dev/null @@ -1,1405 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 27 Feb 2023 18:28:39 -0800 -Subject: [PATCH] Add RegistryAccess for managing Registries - -RegistryAccess is independant from CraftServer and -doesn't require one to be created allowing the -org.bukkit.Registry class to be loaded earlier. - -== AT == -public net.minecraft.server.RegistryLayer STATIC_ACCESS - -diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cd8a6a4c2a63029f8f859765088c227bbd456813 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java -@@ -0,0 +1,154 @@ -+package io.papermc.paper.registry; -+ -+import com.google.common.base.Preconditions; -+import io.papermc.paper.adventure.PaperAdventure; -+import io.papermc.paper.registry.entry.RegistryEntry; -+import java.util.Collections; -+import java.util.IdentityHashMap; -+import java.util.List; -+import java.util.Map; -+import java.util.Objects; -+import net.minecraft.core.Registry; -+import net.minecraft.core.registries.Registries; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Art; -+import org.bukkit.Fluid; -+import org.bukkit.GameEvent; -+import org.bukkit.JukeboxSong; -+import org.bukkit.Keyed; -+import org.bukkit.MusicInstrument; -+import org.bukkit.Sound; -+import org.bukkit.attribute.Attribute; -+import org.bukkit.block.Biome; -+import org.bukkit.block.BlockType; -+import org.bukkit.block.banner.PatternType; -+import org.bukkit.craftbukkit.CraftArt; -+import org.bukkit.craftbukkit.CraftFluid; -+import org.bukkit.craftbukkit.CraftGameEvent; -+import org.bukkit.craftbukkit.CraftJukeboxSong; -+import org.bukkit.craftbukkit.CraftMusicInstrument; -+import org.bukkit.craftbukkit.CraftSound; -+import org.bukkit.craftbukkit.attribute.CraftAttribute; -+import org.bukkit.craftbukkit.block.CraftBiome; -+import org.bukkit.craftbukkit.block.CraftBlockType; -+import org.bukkit.craftbukkit.block.banner.CraftPatternType; -+import org.bukkit.craftbukkit.damage.CraftDamageType; -+import org.bukkit.craftbukkit.enchantments.CraftEnchantment; -+import org.bukkit.craftbukkit.entity.CraftCat; -+import org.bukkit.craftbukkit.entity.CraftFrog; -+import org.bukkit.craftbukkit.entity.CraftVillager; -+import org.bukkit.craftbukkit.entity.CraftWolf; -+import org.bukkit.craftbukkit.generator.structure.CraftStructure; -+import org.bukkit.craftbukkit.generator.structure.CraftStructureType; -+import org.bukkit.craftbukkit.inventory.CraftItemType; -+import org.bukkit.craftbukkit.inventory.CraftMenuType; -+import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial; -+import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern; -+import org.bukkit.craftbukkit.legacy.FieldRename; -+import org.bukkit.craftbukkit.map.CraftMapCursor; -+import org.bukkit.craftbukkit.potion.CraftPotionEffectType; -+import org.bukkit.craftbukkit.util.CraftNamespacedKey; -+import org.bukkit.damage.DamageType; -+import org.bukkit.enchantments.Enchantment; -+import org.bukkit.entity.Cat; -+import org.bukkit.entity.Frog; -+import org.bukkit.entity.Villager; -+import org.bukkit.entity.Wolf; -+import org.bukkit.entity.memory.MemoryKey; -+import org.bukkit.generator.structure.Structure; -+import org.bukkit.generator.structure.StructureType; -+import org.bukkit.inventory.ItemType; -+import org.bukkit.inventory.MenuType; -+import org.bukkit.inventory.meta.trim.TrimMaterial; -+import org.bukkit.inventory.meta.trim.TrimPattern; -+import org.bukkit.map.MapCursor; -+import org.bukkit.potion.PotionEffectType; -+import org.jspecify.annotations.Nullable; -+ -+import static io.papermc.paper.registry.entry.RegistryEntry.apiOnly; -+import static io.papermc.paper.registry.entry.RegistryEntry.entry; -+ -+public final class PaperRegistries { -+ -+ static final List> REGISTRY_ENTRIES; -+ private static final Map, RegistryEntry> BY_REGISTRY_KEY; -+ private static final Map, RegistryEntry> BY_RESOURCE_KEY; -+ static { -+ REGISTRY_ENTRIES = List.of( -+ // built-ins -+ entry(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new), -+ entry(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new), -+ entry(Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, PotionEffectType.class, CraftPotionEffectType::new), -+ entry(Registries.BLOCK, RegistryKey.BLOCK, BlockType.class, CraftBlockType::new), -+ entry(Registries.ITEM, RegistryKey.ITEM, ItemType.class, CraftItemType::new), -+ entry(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT, Cat.Type.class, CraftCat.CraftType::new), -+ entry(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT, Frog.Variant.class, CraftFrog.CraftVariant::new), -+ entry(Registries.VILLAGER_PROFESSION, RegistryKey.VILLAGER_PROFESSION, Villager.Profession.class, CraftVillager.CraftProfession::new), -+ entry(Registries.VILLAGER_TYPE, RegistryKey.VILLAGER_TYPE, Villager.Type.class, CraftVillager.CraftType::new), -+ entry(Registries.MAP_DECORATION_TYPE, RegistryKey.MAP_DECORATION_TYPE, MapCursor.Type.class, CraftMapCursor.CraftType::new), -+ entry(Registries.MENU, RegistryKey.MENU, MenuType.class, CraftMenuType::new), -+ entry(Registries.ATTRIBUTE, RegistryKey.ATTRIBUTE, Attribute.class, CraftAttribute::new), -+ entry(Registries.FLUID, RegistryKey.FLUID, Fluid.class, CraftFluid::new), -+ entry(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT, Sound.class, CraftSound::new), -+ -+ // data-drivens -+ entry(Registries.BIOME, RegistryKey.BIOME, Biome.class, CraftBiome::new).delayed(), -+ entry(Registries.STRUCTURE, RegistryKey.STRUCTURE, Structure.class, CraftStructure::new).delayed(), -+ entry(Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL, TrimMaterial.class, CraftTrimMaterial::new).delayed(), -+ entry(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN, TrimPattern.class, CraftTrimPattern::new).delayed(), -+ entry(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE, DamageType.class, CraftDamageType::new).delayed(), -+ entry(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT, Wolf.Variant.class, CraftWolf.CraftVariant::new).delayed(), -+ entry(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, Enchantment.class, CraftEnchantment::new).withSerializationUpdater(FieldRename.ENCHANTMENT_RENAME).delayed(), -+ entry(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG, JukeboxSong.class, CraftJukeboxSong::new).delayed(), -+ entry(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN, PatternType.class, CraftPatternType::new).delayed(), -+ entry(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT, Art.class, CraftArt::new).delayed(), -+ entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new).delayed(), -+ -+ // api-only -+ apiOnly(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE, PaperSimpleRegistry::entityType), -+ apiOnly(Registries.PARTICLE_TYPE, RegistryKey.PARTICLE_TYPE, PaperSimpleRegistry::particleType), -+ apiOnly(Registries.POTION, RegistryKey.POTION, PaperSimpleRegistry::potion), -+ apiOnly(Registries.MEMORY_MODULE_TYPE, RegistryKey.MEMORY_MODULE_TYPE, () -> (org.bukkit.Registry>) (org.bukkit.Registry) org.bukkit.Registry.MEMORY_MODULE_TYPE) -+ ); -+ final Map, RegistryEntry> byRegistryKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); -+ final Map, RegistryEntry> byResourceKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); -+ for (final RegistryEntry entry : REGISTRY_ENTRIES) { -+ Preconditions.checkState(byRegistryKey.put(entry.apiKey(), entry) == null, "Duplicate api registry key: %s", entry.apiKey()); -+ Preconditions.checkState(byResourceKey.put(entry.mcKey(), entry) == null, "Duplicate mc registry key: %s", entry.mcKey()); -+ } -+ BY_REGISTRY_KEY = Collections.unmodifiableMap(byRegistryKey); -+ BY_RESOURCE_KEY = Collections.unmodifiableMap(byResourceKey); -+ } -+ -+ @SuppressWarnings("unchecked") -+ public static @Nullable RegistryEntry getEntry(final ResourceKey> resourceKey) { -+ return (RegistryEntry) BY_RESOURCE_KEY.get(resourceKey); -+ } -+ -+ @SuppressWarnings("unchecked") -+ public static @Nullable RegistryEntry getEntry(final RegistryKey registryKey) { -+ return (RegistryEntry) BY_REGISTRY_KEY.get(registryKey); -+ } -+ -+ @SuppressWarnings("unchecked") -+ public static RegistryKey registryFromNms(final ResourceKey> registryResourceKey) { -+ return (RegistryKey) Objects.requireNonNull(BY_RESOURCE_KEY.get(registryResourceKey), registryResourceKey + " doesn't have an api RegistryKey").apiKey(); -+ } -+ -+ @SuppressWarnings("unchecked") -+ public static ResourceKey> registryToNms(final RegistryKey registryKey) { -+ return (ResourceKey>) Objects.requireNonNull(BY_REGISTRY_KEY.get(registryKey), registryKey + " doesn't have an mc registry ResourceKey").mcKey(); -+ } -+ -+ public static TypedKey fromNms(final ResourceKey resourceKey) { -+ return TypedKey.create(registryFromNms(resourceKey.registryKey()), CraftNamespacedKey.fromMinecraft(resourceKey.location())); -+ } -+ -+ @SuppressWarnings({"unchecked", "RedundantCast"}) -+ public static ResourceKey toNms(final TypedKey typedKey) { -+ return ResourceKey.create((ResourceKey>) PaperRegistries.registryToNms(typedKey.registryKey()), PaperAdventure.asVanilla(typedKey.key())); -+ } -+ -+ private PaperRegistries() { -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4bf7915867dbe762ef0b070d67d5f7b7d1ee4f03 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java -@@ -0,0 +1,122 @@ -+package io.papermc.paper.registry; -+ -+import io.papermc.paper.registry.entry.ApiRegistryEntry; -+import io.papermc.paper.registry.entry.RegistryEntry; -+import io.papermc.paper.registry.legacy.DelayedRegistry; -+import io.papermc.paper.registry.legacy.DelayedRegistryEntry; -+import io.papermc.paper.registry.legacy.LegacyRegistryIdentifiers; -+import java.util.Map; -+import java.util.NoSuchElementException; -+import java.util.Set; -+import java.util.concurrent.ConcurrentHashMap; -+import java.util.stream.Collectors; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+import org.bukkit.Registry; -+import org.jetbrains.annotations.VisibleForTesting; -+import org.jspecify.annotations.Nullable; -+ -+public class PaperRegistryAccess implements RegistryAccess { -+ -+ // We store the API registries in a memoized supplier, so they can be created on-demand. -+ // These suppliers are added to this map right after the instance of nms.Registry is created before it is loaded. -+ // We want to do registration there, so we have access to the nms.Registry instance in order to wrap it in a CraftRegistry instance. -+ // The memoized Supplier is needed because we *can't* instantiate any CraftRegistry class until **all** the BuiltInRegistries have been added -+ // to this map because that would class-load org.bukkit.Registry which would query this map. -+ private final Map, RegistryHolder> registries = new ConcurrentHashMap<>(); // is "identity" because RegistryKey overrides equals and hashCode -+ -+ public static PaperRegistryAccess instance() { -+ return (PaperRegistryAccess) RegistryAccessHolder.INSTANCE.orElseThrow(() -> new IllegalStateException("No RegistryAccess implementation found")); -+ } -+ -+ @VisibleForTesting -+ public Set> getLoadedServerBackedRegistries() { -+ return this.registries.keySet().stream().filter(registryHolder -> !(PaperRegistries.getEntry(registryHolder) instanceof ApiRegistryEntry)).collect(Collectors.toUnmodifiableSet()); -+ } -+ -+ @SuppressWarnings("unchecked") -+ @Deprecated(forRemoval = true) -+ @Override -+ public @Nullable Registry getRegistry(final Class type) { -+ final RegistryKey registryKey = byType(type); -+ // If our mapping from Class -> RegistryKey did not contain the passed type it was either a completely invalid type or a registry -+ // that merely exists as a SimpleRegistry in the org.bukkit.Registry type. We cannot return a registry for these, return null -+ // as per method contract in Bukkit#getRegistry. -+ if (registryKey == null) return null; -+ -+ final RegistryEntry entry = PaperRegistries.getEntry(registryKey); -+ final RegistryHolder registry = (RegistryHolder) this.registries.get(registryKey); -+ if (registry != null) { -+ // if the registry exists, return right away. Since this is the "legacy" method, we return DelayedRegistry -+ // for the non-builtin Registry instances stored as fields in Registry. -+ return registry.get(); -+ } else if (entry instanceof DelayedRegistryEntry) { -+ // if the registry doesn't exist and the entry is marked as "delayed", we create a registry holder that is empty -+ // which will later be filled with the actual registry. This is so the fields on org.bukkit.Registry can be populated with -+ // registries that don't exist at the time org.bukkit.Registry is statically initialized. -+ final RegistryHolder delayedHolder = new RegistryHolder.Delayed<>(); -+ this.registries.put(registryKey, delayedHolder); -+ return delayedHolder.get(); -+ } else { -+ // if the registry doesn't exist yet or doesn't have a delayed entry, just return null -+ return null; -+ } -+ } -+ -+ @SuppressWarnings("unchecked") -+ @Override -+ public Registry getRegistry(final RegistryKey key) { -+ if (PaperRegistries.getEntry(key) == null) { -+ throw new NoSuchElementException(key + " is not a valid registry key"); -+ } -+ final @Nullable RegistryHolder registryHolder = (RegistryHolder) this.registries.get(key); -+ if (registryHolder == null) { -+ throw new IllegalArgumentException(key + " points to a registry that is not available yet"); -+ } -+ // since this is the getRegistry method that uses the modern RegistryKey, we unwrap any DelayedRegistry instances -+ // that might be returned here. I don't think reference equality is required when doing getRegistry(RegistryKey.WOLF_VARIANT) == Registry.WOLF_VARIANT -+ return possiblyUnwrap(registryHolder.get()); -+ } -+ -+ private static Registry possiblyUnwrap(final Registry registry) { -+ if (registry instanceof final DelayedRegistry delayedRegistry) { // if not coming from legacy, unwrap the delayed registry -+ return delayedRegistry.delegate(); -+ } -+ return registry; -+ } -+ -+ public void registerReloadableRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry) { -+ this.registerRegistry(resourceKey, registry, true); -+ } -+ -+ public void registerRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry) { -+ this.registerRegistry(resourceKey, registry, false); -+ } -+ -+ @SuppressWarnings("unchecked") // this method should be called right after any new MappedRegistry instances are created to later be used by the server. -+ private > void registerRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry, final boolean replace) { -+ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(resourceKey); -+ if (entry == null) { // skip registries that don't have API entries -+ return; -+ } -+ final @Nullable RegistryHolder registryHolder = (RegistryHolder) this.registries.get(entry.apiKey()); -+ if (registryHolder == null || replace) { -+ // if the holder doesn't exist yet, or is marked as "replaceable", put it in the map. -+ this.registries.put(entry.apiKey(), entry.createRegistryHolder(registry)); -+ } else { -+ if (registryHolder instanceof RegistryHolder.Delayed && entry instanceof final DelayedRegistryEntry delayedEntry) { -+ // if the registry holder is delayed, and the entry is marked as "delayed", then load the holder with the CraftRegistry instance that wraps the actual nms Registry. -+ ((RegistryHolder.Delayed) registryHolder).loadFrom(delayedEntry, registry); -+ } else { -+ throw new IllegalArgumentException(resourceKey + " has already been created"); -+ } -+ } -+ } -+ -+ @SuppressWarnings("unchecked") -+ @Deprecated -+ @VisibleForTesting -+ public static @Nullable RegistryKey byType(final Class type) { -+ return (RegistryKey) LegacyRegistryIdentifiers.CLASS_TO_KEY_MAP.get(type); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6d134ace042758da722960cbcb48e52508dafd61 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java -@@ -0,0 +1,38 @@ -+package io.papermc.paper.registry; -+ -+import java.util.function.Predicate; -+import net.minecraft.core.registries.BuiltInRegistries; -+import org.bukkit.Keyed; -+import org.bukkit.Particle; -+import org.bukkit.Registry; -+import org.bukkit.entity.EntityType; -+import org.bukkit.potion.PotionType; -+import org.jspecify.annotations.NullMarked; -+ -+@NullMarked -+public class PaperSimpleRegistry & Keyed, M> extends Registry.SimpleRegistry { -+ -+ static Registry entityType() { -+ return new PaperSimpleRegistry<>(EntityType.class, entity -> entity != EntityType.UNKNOWN, BuiltInRegistries.ENTITY_TYPE); -+ } -+ -+ static Registry particleType() { -+ return new PaperSimpleRegistry<>(Particle.class, BuiltInRegistries.PARTICLE_TYPE); -+ } -+ -+ static Registry potion() { -+ return new PaperSimpleRegistry<>(PotionType.class, BuiltInRegistries.POTION); -+ } -+ -+ private final net.minecraft.core.Registry nmsRegistry; -+ -+ protected PaperSimpleRegistry(final Class type, final net.minecraft.core.Registry nmsRegistry) { -+ super(type); -+ this.nmsRegistry = nmsRegistry; -+ } -+ -+ public PaperSimpleRegistry(final Class type, final Predicate predicate, final net.minecraft.core.Registry nmsRegistry) { -+ super(type, predicate); -+ this.nmsRegistry = nmsRegistry; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/RegistryHolder.java b/src/main/java/io/papermc/paper/registry/RegistryHolder.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1b52d4bc868e1e5f84c8416301e193bb9cd315b2 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/RegistryHolder.java -@@ -0,0 +1,44 @@ -+package io.papermc.paper.registry; -+ -+import com.google.common.base.Suppliers; -+import io.papermc.paper.registry.legacy.DelayedRegistry; -+import io.papermc.paper.registry.legacy.DelayedRegistryEntry; -+import java.util.function.Supplier; -+import org.bukkit.Keyed; -+import org.bukkit.Registry; -+ -+public interface RegistryHolder { -+ -+ Registry get(); -+ -+ final class Memoized> implements RegistryHolder { -+ -+ private final Supplier memoizedSupplier; -+ -+ public Memoized(final Supplier supplier) { -+ this.memoizedSupplier = Suppliers.memoize(supplier::get); -+ } -+ -+ public Registry get() { -+ return this.memoizedSupplier.get(); -+ } -+ } -+ -+ final class Delayed> implements RegistryHolder { -+ -+ private final DelayedRegistry delayedRegistry = new DelayedRegistry<>(); -+ -+ @Override -+ public DelayedRegistry get() { -+ return this.delayedRegistry; -+ } -+ -+ void loadFrom(final DelayedRegistryEntry delayedEntry, final net.minecraft.core.Registry registry) { -+ final RegistryHolder delegateHolder = delayedEntry.delegate().createRegistryHolder(registry); -+ if (!(delegateHolder instanceof RegistryHolder.Memoized)) { -+ throw new IllegalArgumentException(delegateHolder + " must be a memoized holder"); -+ } -+ this.delayedRegistry.load(((Memoized) delegateHolder).memoizedSupplier); -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/entry/ApiRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/ApiRegistryEntry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2295b0d145cbaabef5d29482c817575dcbe2ba54 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/entry/ApiRegistryEntry.java -@@ -0,0 +1,27 @@ -+package io.papermc.paper.registry.entry; -+ -+import io.papermc.paper.registry.RegistryHolder; -+import io.papermc.paper.registry.RegistryKey; -+import java.util.function.Supplier; -+import net.minecraft.core.Registry; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+ -+public class ApiRegistryEntry extends BaseRegistryEntry { -+ -+ private final Supplier> registrySupplier; -+ -+ protected ApiRegistryEntry( -+ final ResourceKey> mcKey, -+ final RegistryKey apiKey, -+ final Supplier> registrySupplier -+ ) { -+ super(mcKey, apiKey); -+ this.registrySupplier = registrySupplier; -+ } -+ -+ @Override -+ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { -+ return new RegistryHolder.Memoized<>(this.registrySupplier); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ceb217dbbb84e8bd51365dd47bf91971e364d298 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java -@@ -0,0 +1,27 @@ -+package io.papermc.paper.registry.entry; -+ -+import io.papermc.paper.registry.RegistryKey; -+import net.minecraft.core.Registry; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+ -+public abstract class BaseRegistryEntry implements RegistryEntry { // TODO remove Keyed -+ -+ private final ResourceKey> minecraftRegistryKey; -+ private final RegistryKey apiRegistryKey; -+ -+ protected BaseRegistryEntry(final ResourceKey> minecraftRegistryKey, final RegistryKey apiRegistryKey) { -+ this.minecraftRegistryKey = minecraftRegistryKey; -+ this.apiRegistryKey = apiRegistryKey; -+ } -+ -+ @Override -+ public final ResourceKey> mcKey() { -+ return this.minecraftRegistryKey; -+ } -+ -+ @Override -+ public final RegistryKey apiKey() { -+ return this.apiRegistryKey; -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..45cbc425da64f0bd3290600869ad425d9e6e912b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java -@@ -0,0 +1,48 @@ -+package io.papermc.paper.registry.entry; -+ -+import com.google.common.base.Preconditions; -+import io.papermc.paper.registry.RegistryHolder; -+import io.papermc.paper.registry.RegistryKey; -+import java.util.function.BiFunction; -+import net.minecraft.core.Registry; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.craftbukkit.CraftRegistry; -+import org.bukkit.craftbukkit.util.ApiVersion; -+ -+public class CraftRegistryEntry extends BaseRegistryEntry { // TODO remove Keyed -+ -+ private static final BiFunction EMPTY = (namespacedKey, apiVersion) -> namespacedKey; -+ -+ protected final Class classToPreload; -+ protected final BiFunction minecraftToBukkit; -+ protected BiFunction updater = EMPTY; -+ -+ protected CraftRegistryEntry( -+ final ResourceKey> mcKey, -+ final RegistryKey apiKey, -+ final Class classToPreload, -+ final BiFunction minecraftToBukkit -+ ) { -+ super(mcKey, apiKey); -+ Preconditions.checkArgument(!classToPreload.getPackageName().startsWith("net.minecraft"), classToPreload + " should not be in the net.minecraft package as the class-to-preload"); -+ this.classToPreload = classToPreload; -+ this.minecraftToBukkit = minecraftToBukkit; -+ } -+ -+ @Override -+ public RegistryEntry withSerializationUpdater(final BiFunction updater) { -+ this.updater = updater; -+ return this; -+ } -+ -+ @Override -+ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { -+ return new RegistryHolder.Memoized<>(() -> this.createApiRegistry(nmsRegistry)); -+ } -+ -+ private CraftRegistry createApiRegistry(final Registry nmsRegistry) { -+ return new CraftRegistry<>(this.classToPreload, nmsRegistry, this.minecraftToBukkit, this.updater); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2889d87f0989ae5744cd4c1e57240830aa574155 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java -@@ -0,0 +1,48 @@ -+package io.papermc.paper.registry.entry; -+ -+import io.papermc.paper.registry.RegistryHolder; -+import io.papermc.paper.registry.RegistryKey; -+import io.papermc.paper.registry.legacy.DelayedRegistryEntry; -+import java.util.function.BiFunction; -+import java.util.function.Supplier; -+import net.minecraft.core.Registry; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.craftbukkit.util.ApiVersion; -+ -+public interface RegistryEntry extends RegistryEntryInfo { // TODO remove Keyed -+ -+ RegistryHolder createRegistryHolder(Registry nmsRegistry); -+ -+ default RegistryEntry withSerializationUpdater(final BiFunction updater) { -+ return this; -+ } -+ -+ /** -+ * This should only be used if the registry instance needs to exist early due to the need -+ * to populate a field in {@link org.bukkit.Registry}. Data-driven registries shouldn't exist -+ * as fields, but instead be obtained via {@link io.papermc.paper.registry.RegistryAccess#getRegistry(RegistryKey)} -+ */ -+ @Deprecated -+ default RegistryEntry delayed() { -+ return new DelayedRegistryEntry<>(this); -+ } -+ -+ static RegistryEntry entry( -+ final ResourceKey> mcKey, -+ final RegistryKey apiKey, -+ final Class classToPreload, -+ final BiFunction minecraftToBukkit -+ ) { -+ return new CraftRegistryEntry<>(mcKey, apiKey, classToPreload, minecraftToBukkit); -+ } -+ -+ static RegistryEntry apiOnly( -+ final ResourceKey> mcKey, -+ final RegistryKey apiKey, -+ final Supplier> apiRegistrySupplier -+ ) { -+ return new ApiRegistryEntry<>(mcKey, apiKey, apiRegistrySupplier); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0ae855e80fc9fddfc1feb33c7a9748204828b7cc ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java -@@ -0,0 +1,12 @@ -+package io.papermc.paper.registry.entry; -+ -+import io.papermc.paper.registry.RegistryKey; -+import net.minecraft.core.Registry; -+import net.minecraft.resources.ResourceKey; -+ -+public interface RegistryEntryInfo { -+ -+ ResourceKey> mcKey(); -+ -+ RegistryKey apiKey(); -+} -diff --git a/src/main/java/io/papermc/paper/registry/entry/package-info.java b/src/main/java/io/papermc/paper/registry/entry/package-info.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f04e93aa5ca41ce1cf3b152f827911fdf0dd10cb ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/entry/package-info.java -@@ -0,0 +1,4 @@ -+@NullMarked -+package io.papermc.paper.registry.entry; -+ -+import org.jspecify.annotations.NullMarked; -diff --git a/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ca829b162d4369f845e59b62bb8779fd83fe2ef3 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java -@@ -0,0 +1,57 @@ -+package io.papermc.paper.registry.legacy; -+ -+import java.util.Iterator; -+import java.util.function.Supplier; -+import java.util.stream.Stream; -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Registry; -+import org.jspecify.annotations.Nullable; -+ -+/** -+ * This is to support the now-deprecated fields in {@link Registry} for -+ * data-driven registries. -+ */ -+public final class DelayedRegistry> implements Registry { -+ -+ private @Nullable Supplier delegate; -+ -+ public void load(final Supplier registry) { -+ if (this.delegate != null) { -+ throw new IllegalStateException("Registry already loaded!"); -+ } -+ this.delegate = registry; -+ } -+ -+ public Registry delegate() { -+ if (this.delegate == null) { -+ throw new IllegalStateException("You are trying to access this registry too early!"); -+ } -+ return this.delegate.get(); -+ } -+ -+ @Override -+ public @Nullable T get(final NamespacedKey key) { -+ return this.delegate().get(key); -+ } -+ -+ @Override -+ public T getOrThrow(final NamespacedKey key) { -+ return this.delegate().getOrThrow(key); -+ } -+ -+ @Override -+ public Iterator iterator() { -+ return this.delegate().iterator(); -+ } -+ -+ @Override -+ public Stream stream() { -+ return this.delegate().stream(); -+ } -+ -+ @Override -+ public @Nullable NamespacedKey getKey(final T value) { -+ return this.delegate().getKey(value); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..110b8d559f49f9e4f181b47663962a139a273a72 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java -@@ -0,0 +1,26 @@ -+package io.papermc.paper.registry.legacy; -+ -+import io.papermc.paper.registry.RegistryHolder; -+import io.papermc.paper.registry.RegistryKey; -+import io.papermc.paper.registry.entry.RegistryEntry; -+import net.minecraft.core.Registry; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+ -+public record DelayedRegistryEntry(RegistryEntry delegate) implements RegistryEntry { -+ -+ @Override -+ public ResourceKey> mcKey() { -+ return this.delegate.mcKey(); -+ } -+ -+ @Override -+ public RegistryKey apiKey() { -+ return this.delegate.apiKey(); -+ } -+ -+ @Override -+ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { -+ return this.delegate.createRegistryHolder(nmsRegistry); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java -new file mode 100644 -index 0000000000000000000000000000000000000000..83870816cd4c54f94a3c603ffe41c11e457f3dec ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java -@@ -0,0 +1,33 @@ -+package io.papermc.paper.registry.legacy; -+ -+import com.google.common.collect.ImmutableMap; -+import io.leangen.geantyref.GenericTypeReflector; -+import io.papermc.paper.registry.RegistryKey; -+import java.lang.reflect.Field; -+import java.lang.reflect.ParameterizedType; -+import java.util.Map; -+ -+@Deprecated -+public final class LegacyRegistryIdentifiers { -+ -+ public static final Map, RegistryKey> CLASS_TO_KEY_MAP; -+ -+ static { -+ final ImmutableMap.Builder, RegistryKey> builder = ImmutableMap.builder(); -+ try { -+ for (final Field field : RegistryKey.class.getFields()) { -+ if (field.getType() == RegistryKey.class) { -+ // get the legacy type from the RegistryKey generic parameter on the field -+ final Class legacyType = GenericTypeReflector.erase(((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]); -+ builder.put(legacyType, (RegistryKey) field.get(null)); -+ } -+ } -+ } catch (final ReflectiveOperationException ex) { -+ throw new RuntimeException(ex); -+ } -+ CLASS_TO_KEY_MAP = builder.build(); -+ } -+ -+ private LegacyRegistryIdentifiers() { -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/legacy/package-info.java b/src/main/java/io/papermc/paper/registry/legacy/package-info.java -new file mode 100644 -index 0000000000000000000000000000000000000000..063a8d7a7313d5d685d51df54d9502d72266da49 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/legacy/package-info.java -@@ -0,0 +1,4 @@ -+@NullMarked -+package io.papermc.paper.registry.legacy; -+ -+import org.jspecify.annotations.NullMarked; -diff --git a/src/main/java/io/papermc/paper/registry/package-info.java b/src/main/java/io/papermc/paper/registry/package-info.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ca07ef31161e938d48214992b34cafb712a51513 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/package-info.java -@@ -0,0 +1,4 @@ -+@NullMarked -+package io.papermc.paper.registry; -+ -+import org.jspecify.annotations.NullMarked; -diff --git a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java -index 3f72e30b57fb2a4231e22a2234729408c1240af4..4638ba98dbbdb0f880337347be85a6e0fbed2191 100644 ---- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java -+++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java -@@ -323,6 +323,7 @@ public class BuiltInRegistries { - ResourceKey> key, R registry, BuiltInRegistries.RegistryBootstrap initializer - ) { - Bootstrap.checkBootstrapCalled(() -> "registry " + key.location()); -+ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(registry.key(), registry); // Paper - initialize API registry - ResourceLocation resourceLocation = key.location(); - LOADERS.put(resourceLocation, () -> initializer.run(registry)); - WRITABLE_REGISTRY.register((ResourceKey)key, registry, RegistrationInfo.BUILT_IN); // Paper - decompile fix -diff --git a/src/main/java/net/minecraft/resources/RegistryDataLoader.java b/src/main/java/net/minecraft/resources/RegistryDataLoader.java -index b9b9ec93442423e99def9b2c51aedc955a7799d5..b8c1840eeda982c0c6350e49fae2784a599ef3ce 100644 ---- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java -+++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java -@@ -349,6 +349,7 @@ public class RegistryDataLoader { - - RegistryDataLoader.Loader create(Lifecycle lifecycle, Map, Exception> errors) { - WritableRegistry writableRegistry = new MappedRegistry<>(this.key, lifecycle); -+ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(this.key, writableRegistry); // Paper - initialize API registry - return new RegistryDataLoader.Loader<>(this, writableRegistry, errors); - } - -diff --git a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java -index 257cfce009fb6fcd24d1fddfd8001e9b2a8ae1ae..185752185549ebd5f431932b63d8e5fea50a2cb2 100644 ---- a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java -+++ b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java -@@ -64,6 +64,7 @@ public class ReloadableServerRegistries { - ) { - return CompletableFuture.supplyAsync(() -> { - WritableRegistry writableRegistry = new MappedRegistry<>(type.registryKey(), Lifecycle.experimental()); -+ io.papermc.paper.registry.PaperRegistryAccess.instance().registerReloadableRegistry(type.registryKey(), writableRegistry); // Paper - register reloadable registry - Map map = new HashMap<>(); - SimpleJsonResourceReloadListener.scanDirectory(resourceManager, type.registryKey(), ops, type.codec(), map); - map.forEach((id, value) -> writableRegistry.register(ResourceKey.create(type.registryKey(), id), (T)value, DEFAULT_REGISTRATION_INFO)); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index 0d091c7b328fb70a82f5b5ded7dec61b7cd3d59a..249f0dcad04a35244da6dab837a461bb42aad00a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -127,96 +127,12 @@ public class CraftRegistry implements Registry { - + ", this can happen if a plugin creates its own registry entry with out properly registering it."); - } - -- /** -- * Note: Newly added registries should also be added to RegistriesArgumentProvider in the test package -- * -- * @param bukkitClass the bukkit class of the registry -- * @param registryHolder the minecraft registry holder -- * @return the bukkit registry of the provided class -- */ -- public static Registry createRegistry(Class bukkitClass, RegistryAccess registryHolder) { -- if (bukkitClass == Art.class) { -- return new CraftRegistry<>(Art.class, registryHolder.lookupOrThrow(Registries.PAINTING_VARIANT), CraftArt::new, FieldRename.NONE); -- } -- if (bukkitClass == Attribute.class) { -- return new CraftRegistry<>(Attribute.class, registryHolder.lookupOrThrow(Registries.ATTRIBUTE), CraftAttribute::new, FieldRename.ATTRIBUTE_RENAME); -- } -- if (bukkitClass == Biome.class) { -- return new CraftRegistry<>(Biome.class, registryHolder.lookupOrThrow(Registries.BIOME), CraftBiome::new, FieldRename.BIOME_RENAME); -- } -- if (bukkitClass == Enchantment.class) { -- return new CraftRegistry<>(Enchantment.class, registryHolder.lookupOrThrow(Registries.ENCHANTMENT), CraftEnchantment::new, FieldRename.ENCHANTMENT_RENAME); -- } -- if (bukkitClass == Fluid.class) { -- return new CraftRegistry<>(Fluid.class, registryHolder.lookupOrThrow(Registries.FLUID), CraftFluid::new, FieldRename.NONE); -- } -- if (bukkitClass == GameEvent.class) { -- return new CraftRegistry<>(GameEvent.class, registryHolder.lookupOrThrow(Registries.GAME_EVENT), CraftGameEvent::new, FieldRename.NONE); -- } -- if (bukkitClass == MusicInstrument.class) { -- return new CraftRegistry<>(MusicInstrument.class, registryHolder.lookupOrThrow(Registries.INSTRUMENT), CraftMusicInstrument::new, FieldRename.NONE); -- } -- if (bukkitClass == MenuType.class) { -- return new CraftRegistry<>(MenuType.class, registryHolder.lookupOrThrow(Registries.MENU), CraftMenuType::new, FieldRename.NONE); -- } -- if (bukkitClass == PotionEffectType.class) { -- return new CraftRegistry<>(PotionEffectType.class, registryHolder.lookupOrThrow(Registries.MOB_EFFECT), CraftPotionEffectType::new, FieldRename.NONE); -- } -- if (bukkitClass == Sound.class) { -- return new CraftRegistry<>(Sound.class, registryHolder.lookupOrThrow(Registries.SOUND_EVENT), CraftSound::new, FieldRename.NONE); -- } -- if (bukkitClass == Structure.class) { -- return new CraftRegistry<>(Structure.class, registryHolder.lookupOrThrow(Registries.STRUCTURE), CraftStructure::new, FieldRename.NONE); -- } -- if (bukkitClass == StructureType.class) { -- return new CraftRegistry<>(StructureType.class, registryHolder.lookupOrThrow(Registries.STRUCTURE_TYPE), CraftStructureType::new, FieldRename.NONE); -- } -- if (bukkitClass == Villager.Type.class) { -- return new CraftRegistry<>(Villager.Type.class, registryHolder.lookupOrThrow(Registries.VILLAGER_TYPE), CraftVillager.CraftType::new, FieldRename.NONE); -- } -- if (bukkitClass == Villager.Profession.class) { -- return new CraftRegistry<>(Villager.Profession.class, registryHolder.lookupOrThrow(Registries.VILLAGER_PROFESSION), CraftVillager.CraftProfession::new, FieldRename.NONE); -- } -- if (bukkitClass == TrimMaterial.class) { -- return new CraftRegistry<>(TrimMaterial.class, registryHolder.lookupOrThrow(Registries.TRIM_MATERIAL), CraftTrimMaterial::new, FieldRename.NONE); -- } -- if (bukkitClass == TrimPattern.class) { -- return new CraftRegistry<>(TrimPattern.class, registryHolder.lookupOrThrow(Registries.TRIM_PATTERN), CraftTrimPattern::new, FieldRename.NONE); -- } -- if (bukkitClass == DamageType.class) { -- return new CraftRegistry<>(DamageType.class, registryHolder.lookupOrThrow(Registries.DAMAGE_TYPE), CraftDamageType::new, FieldRename.NONE); -- } -- if (bukkitClass == JukeboxSong.class) { -- return new CraftRegistry<>(JukeboxSong.class, registryHolder.lookupOrThrow(Registries.JUKEBOX_SONG), CraftJukeboxSong::new, FieldRename.NONE); -- } -- if (bukkitClass == Wolf.Variant.class) { -- return new CraftRegistry<>(Wolf.Variant.class, registryHolder.lookupOrThrow(Registries.WOLF_VARIANT), CraftWolf.CraftVariant::new, FieldRename.NONE); -- } -- if (bukkitClass == BlockType.class) { -- return new CraftRegistry<>(BlockType.class, registryHolder.lookupOrThrow(Registries.BLOCK), CraftBlockType::new, FieldRename.NONE); -- } -- if (bukkitClass == ItemType.class) { -- return new CraftRegistry<>(ItemType.class, registryHolder.lookupOrThrow(Registries.ITEM), CraftItemType::new, FieldRename.NONE); -- } -- if (bukkitClass == Frog.Variant.class) { -- return new CraftRegistry<>(Frog.Variant.class, registryHolder.lookupOrThrow(Registries.FROG_VARIANT), CraftFrog.CraftVariant::new, FieldRename.NONE); -- } -- if (bukkitClass == Cat.Type.class) { -- return new CraftRegistry<>(Cat.Type.class, registryHolder.lookupOrThrow(Registries.CAT_VARIANT), CraftCat.CraftType::new, FieldRename.NONE); -- } -- if (bukkitClass == MapCursor.Type.class) { -- return new CraftRegistry<>(MapCursor.Type.class, registryHolder.lookupOrThrow(Registries.MAP_DECORATION_TYPE), CraftMapCursor.CraftType::new, FieldRename.NONE); -- } -- if (bukkitClass == PatternType.class) { -- return new CraftRegistry<>(PatternType.class, registryHolder.lookupOrThrow(Registries.BANNER_PATTERN), CraftPatternType::new, FieldRename.NONE); -- } -- -- return null; -- } -+ // Paper - move to PaperRegistries - -+ // Paper - NOTE: As long as all uses of the method below relate to *serialization* via ConfigurationSerializable, it's fine - public static B get(Registry bukkit, NamespacedKey namespacedKey, ApiVersion apiVersion) { - if (bukkit instanceof CraftRegistry craft) { -- return craft.get(namespacedKey, apiVersion); -+ return craft.get(craft.serializationUpdater.apply(namespacedKey, apiVersion)); // Paper - } - - if (bukkit instanceof Registry.SimpleRegistry simple) { -@@ -234,23 +150,21 @@ public class CraftRegistry implements Registry { - return bukkit.get(namespacedKey); - } - -- private final Class bukkitClass; -+ private final Class bukkitClass; // Paper - relax preload class - private final Map cache = new HashMap<>(); - private final net.minecraft.core.Registry minecraftRegistry; - private final BiFunction minecraftToBukkit; -- private final BiFunction updater; -+ private final BiFunction serializationUpdater; // Paper - rename to make it *clear* what it is *only* for - private boolean init; - -- public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit, BiFunction updater) { -+ public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit, BiFunction serializationUpdater) { // Paper - relax preload class - this.bukkitClass = bukkitClass; - this.minecraftRegistry = minecraftRegistry; - this.minecraftToBukkit = minecraftToBukkit; -- this.updater = updater; -+ this.serializationUpdater = serializationUpdater; - } - -- public B get(NamespacedKey namespacedKey, ApiVersion apiVersion) { -- return this.get(this.updater.apply(namespacedKey, apiVersion)); -- } -+ // Paper - inline into CraftRegistry#get(Registry, NamespacedKey, ApiVersion) above - - @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 f75d73402cf633254fe1ef4e919f09db48165190..5ae8f646083fb580ac8d28fcbfe8ed2208b45d09 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 { - protected final DedicatedServer console; - protected final DedicatedPlayerList playerList; - private final Map worlds = new LinkedHashMap(); -- private final Map, Registry> registries = new HashMap<>(); -+ // private final Map, Registry> registries = new HashMap<>(); // Paper - replace with RegistryAccess - private YamlConfiguration configuration; - private YamlConfiguration commandsConfiguration; - private final Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); -@@ -431,6 +431,7 @@ public final class CraftServer implements Server { - } - - private void loadCompatibilities() { -+ if (true) return; // Paper - Big nope - ConfigurationSection compatibilities = this.configuration.getConfigurationSection("settings.compatibility"); - if (compatibilities == null) { - this.activeCompatibilities = Collections.emptySet(); -@@ -2754,7 +2755,7 @@ public final class CraftServer implements Server { - - @Override - public Registry getRegistry(Class aClass) { -- return (Registry) this.registries.computeIfAbsent(aClass, key -> CraftRegistry.createRegistry(aClass, this.console.registryAccess())); -+ return io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(aClass); // Paper - replace with RegistryAccess - } - - @Deprecated -diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java b/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java -index 091e11934bddb180f0b2e51efb3921c62275d41d..12fe2f8d0dcb715545e071023490a32125b9c4a4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java -+++ b/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java -@@ -51,11 +51,14 @@ public class FieldRename { - }; - } - -- @RequireCompatibility("allow-old-keys-in-registry") -- public static T get(Registry registry, NamespacedKey namespacedKey) { -- // We don't have version-specific changes, so just use current, and don't inject a version -- return CraftRegistry.get(registry, namespacedKey, ApiVersion.CURRENT); -- } -+ // Paper start - absolutely not, having this as an expectation for plugin developers opens a huge -+ // can of worms in the future, especially if mojang comes back and reuses some old key -+ //@RequireCompatibility("allow-old-keys-in-registry") -+ //public static T get(Registry registry, NamespacedKey namespacedKey) { -+ // // We don't have version-specific changes, so just use current, and don't inject a version -+ // return CraftRegistry.get(registry, namespacedKey, ApiVersion.CURRENT); -+ //} -+ // Paper end - - // PatternType - private static final FieldRenameData PATTERN_TYPE_DATA = FieldRenameData.Builder.newBuilder() -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -index 61d617d4abb9c9cf5c711459aa98c8b173597a9a..c9b789c2a904c2caff516ee9aeff4a6b368766f4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -@@ -220,20 +220,10 @@ public class Commodore { - - public byte[] convert(byte[] b, final String pluginName, final ApiVersion pluginVersion, final Set activeCompatibilities) { - final boolean modern = pluginVersion.isNewerThanOrSameAs(ApiVersion.FLATTENING); -- final boolean enumCompatibility = pluginVersion.isOlderThanOrSameAs(ApiVersion.getOrCreateVersion("1.20.6")) && activeCompatibilities.contains("enum-compatibility-mode"); - ClassReader cr = new ClassReader(b); - ClassWriter cw = new ClassWriter(cr, 0); - -- List methodEnumSignatures = Commodore.getMethodSignatures(b); -- Multimap enumLessToEnum = HashMultimap.create(); -- for (String method : methodEnumSignatures) { -- enumLessToEnum.put(method.replace("Ljava/lang/Enum;", "Ljava/lang/Object;"), method); -- } -- - ClassVisitor visitor = cw; -- if (enumCompatibility) { -- visitor = new LimitedClassRemapper(cw, new SimpleRemapper(Commodore.ENUM_RENAMES)); -- } - - visitor = io.papermc.paper.pluginremap.reflect.ReflectionRemapper.visitor(visitor); // Paper - cr.accept(new ClassRemapper(new ClassVisitor(Opcodes.ASM9, visitor) { -@@ -300,15 +290,6 @@ public class Commodore { - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { -- if (enumCompatibility && (access & Opcodes.ACC_SYNTHETIC) != 0 && (access & Opcodes.ACC_BRIDGE) != 0 && desc.contains("Ljava/lang/Object;")) { -- // SPIGOT-7820: Do not use object method if enum method is present -- // The object method does only redirect to the enum method -- Collection result = enumLessToEnum.get(desc.replace("Ljava/lang/Enum;", "Ljava/lang/Object;") + " " + name); -- if (result.size() == 2) { -- name = name + "_BUKKIT_UNUSED"; -- } -- } -- - return new MethodVisitor(this.api, super.visitMethod(access, name, desc, signature, exceptions)) { - // Paper start - Plugin rewrites - @Override -diff --git a/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess b/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess -new file mode 100644 -index 0000000000000000000000000000000000000000..8a083d45004f82fc9c51c219fb20f34624adb501 ---- /dev/null -+++ b/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess -@@ -0,0 +1 @@ -+io.papermc.paper.registry.PaperRegistryAccess -diff --git a/src/main/resources/configurations/bukkit.yml b/src/main/resources/configurations/bukkit.yml -index 543e37737bc6fdca23ed9ed0606805d345515a5a..eef7c125b2689f29cae5464659eacdf33f5695b2 100644 ---- a/src/main/resources/configurations/bukkit.yml -+++ b/src/main/resources/configurations/bukkit.yml -@@ -23,9 +23,6 @@ settings: - shutdown-message: Server closed - minimum-api: none - use-map-color-cache: true -- compatibility: -- allow-old-keys-in-registry: false -- enum-compatibility-mode: false - spawn-limits: - monsters: 70 - animals: 10 -diff --git a/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a80b0ded74c0be657e734de61cbf5e32e16c26a8 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java -@@ -0,0 +1,21 @@ -+package io.papermc.paper.registry; -+ -+import org.bukkit.GameEvent; -+import org.bukkit.MusicInstrument; -+import org.bukkit.inventory.meta.trim.TrimPattern; -+import org.bukkit.support.environment.VanillaFeature; -+import org.junit.jupiter.api.Test; -+ -+import static org.junit.jupiter.api.Assertions.assertSame; -+ -+@Deprecated -+@VanillaFeature -+class LegacyRegistryIdentifierTest { -+ -+ @Test -+ void testSeveralConversions() { -+ assertSame(RegistryKey.GAME_EVENT, PaperRegistryAccess.byType(GameEvent.class)); -+ assertSame(RegistryKey.TRIM_PATTERN, PaperRegistryAccess.byType(TrimPattern.class)); -+ assertSame(RegistryKey.INSTRUMENT, PaperRegistryAccess.byType(MusicInstrument.class)); -+ } -+} -diff --git a/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java -index d8857a05858585113bc7efde3416748effb53d01..41c38b1b6d25c7a7ed08d70b19f5f4a70fc2df94 100644 ---- a/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java -+++ b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java -@@ -1,15 +1,19 @@ - package io.papermc.paper.registry; - -+import io.papermc.paper.registry.entry.RegistryEntry; - import java.util.Optional; - import java.util.stream.Stream; - import net.minecraft.core.Registry; - import net.minecraft.resources.ResourceKey; - import net.minecraft.resources.ResourceLocation; --import org.bukkit.support.AbstractTestingBase; -+import org.bukkit.support.RegistryHelper; -+import org.bukkit.support.environment.AllFeatures; -+import org.checkerframework.checker.nullness.qual.Nullable; - import org.junit.jupiter.api.BeforeAll; - import org.junit.jupiter.params.ParameterizedTest; - import org.junit.jupiter.params.provider.MethodSource; - -+import static org.junit.jupiter.api.Assertions.assertNotNull; - import static org.junit.jupiter.api.Assertions.assertTrue; - - @AllFeatures -@@ -29,6 +33,12 @@ class RegistryKeyTest { - void testApiRegistryKeysExist(final RegistryKey key) { - final Optional> registry = RegistryHelper.getRegistry().lookup(ResourceKey.createRegistryKey(ResourceLocation.parse(key.key().asString()))); - assertTrue(registry.isPresent(), "Missing vanilla registry for " + key.key().asString()); -+ } - -+ @ParameterizedTest -+ @MethodSource("data") -+ void testRegistryEntryExists(final RegistryKey key) { -+ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(key); -+ assertNotNull(entry, "Missing PaperRegistries entry for " + key); - } - } -diff --git a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java -index b65a3ee68c177da7ef5a57608187dc1672257c7f..c1016e0eb00e952551370c874e8d678fef8ba3dc 100644 ---- a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java -+++ b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java -@@ -22,14 +22,17 @@ public class RegistryArgumentAddedTest { - // Make sure every registry is created - Class.forName(Registry.class.getName()); - -- Set> loadedRegistries = new HashSet<>(AllFeaturesExtension.getRealRegistries().keySet()); -- Set> notFound = new HashSet<>(); -+ // Paper start -+ Set> loadedRegistries = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap<>()); -+ loadedRegistries.addAll(io.papermc.paper.registry.PaperRegistryAccess.instance().getLoadedServerBackedRegistries()); -+ // Paper end -+ Set> notFound = new HashSet<>(); // Paper - - RegistriesArgumentProvider - .getData() - .map(Arguments::get) - .map(array -> array[0]) -- .map(clazz -> (Class) clazz) -+ .map(clazz -> (io.papermc.paper.registry.RegistryKey) clazz) // Paper - .forEach(clazz -> { - if (!loadedRegistries.remove(clazz)) { - notFound.add(clazz); -diff --git a/src/test/java/org/bukkit/registry/RegistryConversionTest.java b/src/test/java/org/bukkit/registry/RegistryConversionTest.java -index e97328b95973db52d44bc4d0aefd8eb69f2ebdea..01e351f4e292efe78fc1a1db0f31b2c0a313b101 100644 ---- a/src/test/java/org/bukkit/registry/RegistryConversionTest.java -+++ b/src/test/java/org/bukkit/registry/RegistryConversionTest.java -@@ -41,9 +41,9 @@ public class RegistryConversionTest { - - @Order(1) - @RegistriesTest -- public void testHandleableImplementation(Class clazz) { -+ public void testHandleableImplementation(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper - Set> notImplemented = new HashSet<>(); -- Registry registry = Bukkit.getRegistry(clazz); -+ Registry registry = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(type); // Paper - - for (Keyed item : registry) { - if (!(item instanceof Handleable)) { -@@ -63,7 +63,7 @@ public class RegistryConversionTest { - - @Order(2) - @RegistriesTest -- public void testMinecraftToBukkitPresent(Class clazz, ResourceKey> registryKey, -+ public void testMinecraftToBukkitPresent(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, - Class craftClazz, Class minecraftClazz, boolean newMethod) { - String methodName = (newMethod) ? RegistryConversionTest.MINECRAFT_TO_BUKKIT_NEW : RegistryConversionTest.MINECRAFT_TO_BUKKIT; - Method method = null; -@@ -112,7 +112,7 @@ public class RegistryConversionTest { - - @Order(2) - @RegistriesTest -- public void testBukkitToMinecraftPresent(Class clazz, ResourceKey> registryKey, -+ public void testBukkitToMinecraftPresent(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, - Class craftClazz, Class minecraftClazz, boolean newMethod) { - String methodName = (newMethod) ? RegistryConversionTest.BUKKIT_TO_MINECRAFT_NEW : RegistryConversionTest.BUKKIT_TO_MINECRAFT; - Method method = null; -@@ -159,9 +159,9 @@ public class RegistryConversionTest { - """, minecraftClazz.getName(), methodName, clazz.getSimpleName()); - } - -- @Order(2) -+ @Order(3) - @RegistriesTest -- public void testMinecraftToBukkitNullValue(Class clazz) throws IllegalAccessException { -+ public void testMinecraftToBukkitNullValue(io.papermc.paper.registry.RegistryKey type, Class clazz) throws IllegalAccessException { // Paper - this.checkValidMinecraftToBukkit(clazz); - - try { -@@ -180,7 +180,7 @@ public class RegistryConversionTest { - - @Order(3) - @RegistriesTest -- public void testBukkitToMinecraftNullValue(Class clazz) throws IllegalAccessException { -+ public void testBukkitToMinecraftNullValue(io.papermc.paper.registry.RegistryKey type, Class clazz) throws IllegalAccessException { // Paper - this.checkValidBukkitToMinecraft(clazz); - - try { -@@ -199,14 +199,14 @@ public class RegistryConversionTest { - - @Order(3) - @RegistriesTest -- public void testMinecraftToBukkit(Class clazz) { -+ public void testMinecraftToBukkit(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper - this.checkValidMinecraftToBukkit(clazz); - this.checkValidHandle(clazz); - - Map notMatching = new HashMap<>(); - Method method = RegistryConversionTest.MINECRAFT_TO_BUKKIT_METHODS.get(clazz); - -- RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> { -+ RegistryArgumentProvider.getValues(type).map(Arguments::get).forEach(arguments -> { // Paper - Keyed bukkit = (Keyed) arguments[0]; - Object minecraft = arguments[1]; - -@@ -230,14 +230,14 @@ public class RegistryConversionTest { - - @Order(3) - @RegistriesTest -- public void testBukkitToMinecraft(Class clazz) { -+ public void testBukkitToMinecraft(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper - this.checkValidBukkitToMinecraft(clazz); - this.checkValidHandle(clazz); - - Map notMatching = new HashMap<>(); - Method method = RegistryConversionTest.BUKKIT_TO_MINECRAFT_METHODS.get(clazz); - -- RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> { -+ RegistryArgumentProvider.getValues(type).map(Arguments::get).forEach(arguments -> { // Paper - Keyed bukkit = (Keyed) arguments[0]; - Object minecraft = arguments[1]; - -@@ -265,7 +265,7 @@ public class RegistryConversionTest { - */ - @Order(3) - @RegistriesTest -- public void testMinecraftToBukkitNoValidMinecraft(Class clazz, ResourceKey> registryKey, -+ public void testMinecraftToBukkitNoValidMinecraft(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, // Paper - Class craftClazz, Class minecraftClazz) throws IllegalAccessException { - this.checkValidMinecraftToBukkit(clazz); - -diff --git a/src/test/java/org/bukkit/support/extension/AllFeaturesExtension.java b/src/test/java/org/bukkit/support/extension/AllFeaturesExtension.java -index e9eb521419bbacb03d7000ace355f2a9f5a6a9c5..8fef8421e3cf87913746a314a477634bd3e99300 100644 ---- a/src/test/java/org/bukkit/support/extension/AllFeaturesExtension.java -+++ b/src/test/java/org/bukkit/support/extension/AllFeaturesExtension.java -@@ -39,22 +39,7 @@ public class AllFeaturesExtension extends BaseExtension { - - Bukkit.setServer(server); - -- when(server.getRegistry(any())) -- .then(invocation -> { -- Class keyed = invocation.getArgument(0); -- if (spyRegistries.containsKey(keyed)) { -- return spyRegistries.get(keyed); -- } -- -- Registry registry = CraftRegistry.createRegistry(keyed, RegistryHelper.getRegistry()); -- realRegistries.put(keyed, registry); -- -- Registry spy = mock(registry.getClass(), withSettings().stubOnly().spiedInstance(registry).defaultAnswer(CALLS_REAL_METHODS)); -- -- spyRegistries.put(keyed, spy); -- -- return spy; -- }); -+ // Paper - Add RegistryAccess for managing registries - replaced with registry access - - CraftRegistry.setMinecraftRegistry(RegistryHelper.getRegistry()); - } -diff --git a/src/test/java/org/bukkit/support/extension/LegacyExtension.java b/src/test/java/org/bukkit/support/extension/LegacyExtension.java -index 94cf52cf7603e6814682c92b26fcf03a8b927838..c9c3227c3b7fa36ed80f2dc828885a0128e1e3d0 100644 ---- a/src/test/java/org/bukkit/support/extension/LegacyExtension.java -+++ b/src/test/java/org/bukkit/support/extension/LegacyExtension.java -@@ -30,11 +30,7 @@ public class LegacyExtension extends BaseExtension { - - Bukkit.setServer(server); - -- when(server.getRegistry(any())) -- .then(invocation -> { -- Class keyed = invocation.getArgument(0); -- return registries.computeIfAbsent(keyed, k -> CraftRegistry.createRegistry(keyed, RegistryHelper.getRegistry())); -- }); -+ // Paper - Add RegistryAccess for managing registries - replaced with registry access - - CraftRegistry.setMinecraftRegistry(RegistryHelper.getRegistry()); - } -diff --git a/src/test/java/org/bukkit/support/extension/SlowExtension.java b/src/test/java/org/bukkit/support/extension/SlowExtension.java -index e0ce6836d4365c36303f6c675a75ef6a9b047b92..87364f223fbd6185b041138550fcb6e3ed07d1ae 100644 ---- a/src/test/java/org/bukkit/support/extension/SlowExtension.java -+++ b/src/test/java/org/bukkit/support/extension/SlowExtension.java -@@ -30,11 +30,7 @@ public class SlowExtension extends BaseExtension { - - Bukkit.setServer(server); - -- when(server.getRegistry(any())) -- .then(invocation -> { -- Class keyed = invocation.getArgument(0); -- return registries.computeIfAbsent(keyed, k -> CraftRegistry.createRegistry(keyed, RegistryHelper.getRegistry())); -- }); -+ // Paper - Add RegistryAccess for managing registries - replaced with registry access - - CraftRegistry.setMinecraftRegistry(RegistryHelper.getRegistry()); - } -diff --git a/src/test/java/org/bukkit/support/extension/VanillaFeatureExtension.java b/src/test/java/org/bukkit/support/extension/VanillaFeatureExtension.java -index bbd5dd5b27937ddc3d8c57f2b604331495b0f311..626c3033e36897846fe84a77d05e2e91a15598e5 100644 ---- a/src/test/java/org/bukkit/support/extension/VanillaFeatureExtension.java -+++ b/src/test/java/org/bukkit/support/extension/VanillaFeatureExtension.java -@@ -30,11 +30,7 @@ public class VanillaFeatureExtension extends BaseExtension { - - Bukkit.setServer(server); - -- when(server.getRegistry(any())) -- .then(invocation -> { -- Class keyed = invocation.getArgument(0); -- return registries.computeIfAbsent(keyed, k -> CraftRegistry.createRegistry(keyed, RegistryHelper.getRegistry())); -- }); -+ // Paper - Add RegistryAccess for managing registries - replaced with registry access - - CraftRegistry.setMinecraftRegistry(RegistryHelper.getRegistry()); - } -diff --git a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java -index bfec6280e8b753a29ad2d9eb88808beb79ec65ea..b717a5ffa567781b0687bbe238b62844214db284 100644 ---- a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java -+++ b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java -@@ -1,6 +1,7 @@ - package org.bukkit.support.provider; - - import com.google.common.collect.Lists; -+import io.papermc.paper.registry.RegistryKey; - import java.util.List; - import java.util.stream.Stream; - import net.minecraft.core.registries.Registries; -@@ -73,41 +74,40 @@ public class RegistriesArgumentProvider implements ArgumentsProvider { - private static final List DATA = Lists.newArrayList(); - - static { -- // Order: Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class -- register(Art.class, Registries.PAINTING_VARIANT, CraftArt.class, PaintingVariant.class); -- register(Attribute.class, Registries.ATTRIBUTE, CraftAttribute.class, net.minecraft.world.entity.ai.attributes.Attribute.class); -- register(Biome.class, Registries.BIOME, CraftBiome.class, net.minecraft.world.level.biome.Biome.class); -- register(Enchantment.class, Registries.ENCHANTMENT, CraftEnchantment.class, net.minecraft.world.item.enchantment.Enchantment.class); -- register(Fluid.class, Registries.FLUID, CraftFluid.class, net.minecraft.world.level.material.Fluid.class); -- register(GameEvent.class, Registries.GAME_EVENT, CraftGameEvent.class, net.minecraft.world.level.gameevent.GameEvent.class); -- register(MusicInstrument.class, Registries.INSTRUMENT, CraftMusicInstrument.class, Instrument.class); -- register(MenuType.class, Registries.MENU, CraftMenuType.class, net.minecraft.world.inventory.MenuType.class); -- register(PotionEffectType.class, Registries.MOB_EFFECT, CraftPotionEffectType.class, MobEffect.class); -- register(Sound.class, Registries.SOUND_EVENT, CraftSound.class, SoundEvent.class); -- register(Structure.class, Registries.STRUCTURE, CraftStructure.class, net.minecraft.world.level.levelgen.structure.Structure.class); -- register(StructureType.class, Registries.STRUCTURE_TYPE, CraftStructureType.class, net.minecraft.world.level.levelgen.structure.StructureType.class); -- register(Villager.Type.class, Registries.VILLAGER_TYPE, CraftVillager.CraftType.class, VillagerType.class); -- register(Villager.Profession.class, Registries.VILLAGER_PROFESSION, CraftVillager.CraftProfession.class, VillagerProfession.class); -- register(TrimMaterial.class, Registries.TRIM_MATERIAL, CraftTrimMaterial.class, net.minecraft.world.item.equipment.trim.TrimMaterial.class); -- register(TrimPattern.class, Registries.TRIM_PATTERN, CraftTrimPattern.class, net.minecraft.world.item.equipment.trim.TrimPattern.class); -- register(DamageType.class, Registries.DAMAGE_TYPE, CraftDamageType.class, net.minecraft.world.damagesource.DamageType.class); -- register(JukeboxSong.class, Registries.JUKEBOX_SONG, CraftJukeboxSong.class, net.minecraft.world.item.JukeboxSong.class); -- register(Wolf.Variant.class, Registries.WOLF_VARIANT, CraftWolf.CraftVariant.class, WolfVariant.class); -- register(ItemType.class, Registries.ITEM, CraftItemType.class, net.minecraft.world.item.Item.class, true); -- register(BlockType.class, Registries.BLOCK, CraftBlockType.class, net.minecraft.world.level.block.Block.class, true); -- register(Frog.Variant.class, Registries.FROG_VARIANT, CraftFrog.CraftVariant.class, FrogVariant.class); -- register(Cat.Type.class, Registries.CAT_VARIANT, CraftCat.CraftType.class, CatVariant.class); -- register(MapCursor.Type.class, Registries.MAP_DECORATION_TYPE, CraftMapCursor.CraftType.class, MapDecorationType.class); -- register(PatternType.class, Registries.BANNER_PATTERN, CraftPatternType.class, BannerPattern.class); -- -+ // Order: RegistryKey, Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class -+ register(RegistryKey.PAINTING_VARIANT, Art.class, Registries.PAINTING_VARIANT, CraftArt.class, PaintingVariant.class); -+ register(RegistryKey.ATTRIBUTE, Attribute.class, Registries.ATTRIBUTE, CraftAttribute.class, net.minecraft.world.entity.ai.attributes.Attribute.class); -+ register(RegistryKey.BIOME, Biome.class, Registries.BIOME, CraftBiome.class, net.minecraft.world.level.biome.Biome.class); -+ register(RegistryKey.ENCHANTMENT, Enchantment.class, Registries.ENCHANTMENT, CraftEnchantment.class, net.minecraft.world.item.enchantment.Enchantment.class); -+ register(RegistryKey.FLUID, Fluid.class, Registries.FLUID, CraftFluid.class, net.minecraft.world.level.material.Fluid.class); -+ register(RegistryKey.GAME_EVENT, GameEvent.class, Registries.GAME_EVENT, CraftGameEvent.class, net.minecraft.world.level.gameevent.GameEvent.class); -+ register(RegistryKey.INSTRUMENT, MusicInstrument.class, Registries.INSTRUMENT, CraftMusicInstrument.class, Instrument.class); -+ register(RegistryKey.MOB_EFFECT, PotionEffectType.class, Registries.MOB_EFFECT, CraftPotionEffectType.class, MobEffect.class); -+ register(RegistryKey.SOUND_EVENT, Sound.class, Registries.SOUND_EVENT, CraftSound.class, SoundEvent.class); -+ register(RegistryKey.STRUCTURE, Structure.class, Registries.STRUCTURE, CraftStructure.class, net.minecraft.world.level.levelgen.structure.Structure.class); -+ register(RegistryKey.STRUCTURE_TYPE, StructureType.class, Registries.STRUCTURE_TYPE, CraftStructureType.class, net.minecraft.world.level.levelgen.structure.StructureType.class); -+ register(RegistryKey.VILLAGER_TYPE, Villager.Type.class, Registries.VILLAGER_TYPE, CraftVillager.CraftType.class, VillagerType.class); -+ register(RegistryKey.VILLAGER_PROFESSION, Villager.Profession.class, Registries.VILLAGER_PROFESSION, CraftVillager.CraftProfession.class, VillagerProfession.class); -+ register(RegistryKey.TRIM_MATERIAL, TrimMaterial.class, Registries.TRIM_MATERIAL, CraftTrimMaterial.class, net.minecraft.world.item.equipment.trim.TrimMaterial.class); -+ register(RegistryKey.TRIM_PATTERN, TrimPattern.class, Registries.TRIM_PATTERN, CraftTrimPattern.class, net.minecraft.world.item.equipment.trim.TrimPattern.class); -+ register(RegistryKey.DAMAGE_TYPE, DamageType.class, Registries.DAMAGE_TYPE, CraftDamageType.class, net.minecraft.world.damagesource.DamageType.class); -+ register(RegistryKey.JUKEBOX_SONG, JukeboxSong.class, Registries.JUKEBOX_SONG, CraftJukeboxSong.class, net.minecraft.world.item.JukeboxSong.class); -+ register(RegistryKey.WOLF_VARIANT, Wolf.Variant.class, Registries.WOLF_VARIANT, CraftWolf.CraftVariant.class, WolfVariant.class); -+ register(RegistryKey.ITEM, ItemType.class, Registries.ITEM, CraftItemType.class, net.minecraft.world.item.Item.class, true); -+ register(RegistryKey.BLOCK, BlockType.class, Registries.BLOCK, CraftBlockType.class, net.minecraft.world.level.block.Block.class, true); -+ register(RegistryKey.FROG_VARIANT, Frog.Variant.class, Registries.FROG_VARIANT, CraftFrog.CraftVariant.class, FrogVariant.class); -+ register(RegistryKey.CAT_VARIANT, Cat.Type.class, Registries.CAT_VARIANT, CraftCat.CraftType.class, CatVariant.class); -+ register(RegistryKey.MAP_DECORATION_TYPE, MapCursor.Type.class, Registries.MAP_DECORATION_TYPE, CraftMapCursor.CraftType.class, MapDecorationType.class); -+ register(RegistryKey.BANNER_PATTERN, PatternType.class, Registries.BANNER_PATTERN, CraftPatternType.class, BannerPattern.class); -+ register(RegistryKey.MENU, MenuType.class, Registries.MENU, CraftMenuType.class, net.minecraft.world.inventory.MenuType.class); - } - -- private static void register(Class bukkit, ResourceKey registry, Class craft, Class minecraft) { -- RegistriesArgumentProvider.register(bukkit, registry, craft, minecraft, false); -+ private static void register(RegistryKey registryKey, Class bukkit, ResourceKey registry, Class craft, Class minecraft) { // Paper -+ RegistriesArgumentProvider.register(registryKey, bukkit, registry, craft, minecraft, false); - } - -- private static void register(Class bukkit, ResourceKey registry, Class craft, Class minecraft, boolean newClass) { -- RegistriesArgumentProvider.DATA.add(Arguments.of(bukkit, registry, craft, minecraft, newClass)); -+ private static void register(RegistryKey registryKey, Class bukkit, ResourceKey registry, Class craft, Class minecraft, boolean newClass) { // Paper -+ RegistriesArgumentProvider.DATA.add(Arguments.of(registryKey, bukkit, registry, craft, minecraft, newClass)); - } - - @Override -diff --git a/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java b/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java -index f2ceb5e67536dfa5de792dc64a7898fd2e8aa810..beb5fc9e721f5de54064c3d241df9ca9f4cd4f65 100644 ---- a/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java -+++ b/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java -@@ -22,11 +22,11 @@ public class RegistryArgumentProvider implements ArgumentsProvider, AnnotationCo - - @Override - public Stream provideArguments(ExtensionContext extensionContext) throws Exception { -- return RegistryArgumentProvider.getValues(this.registryType); -+ return RegistryArgumentProvider.getValues(io.papermc.paper.registry.PaperRegistryAccess.byType(this.registryType)); // Paper - } - -- public static Stream getValues(Class registryType) { -- Registry registry = Bukkit.getRegistry(registryType); -+ public static Stream getValues(io.papermc.paper.registry.RegistryKey registryType) { // Paper -+ Registry registry = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(registryType); // Paper - return registry.stream().map(keyed -> (Handleable) keyed) - .map(handleAble -> Arguments.of(handleAble, handleAble.getHandle())); - } diff --git a/patches/server/0464-Add-StructuresLocateEvent.patch b/patches/server/0464-Add-StructuresLocateEvent.patch new file mode 100644 index 0000000000..6f3d0638ff --- /dev/null +++ b/patches/server/0464-Add-StructuresLocateEvent.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dfsek +Date: Wed, 16 Sep 2020 01:12:29 -0700 +Subject: [PATCH] Add StructuresLocateEvent + +Co-authored-by: Jake Potrebic + +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 0acf8b62ddb5e005f8f861558934e8afc8673725..416b1afcbab093f45900a4d55708609ba5a7de7a 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -127,6 +127,24 @@ public abstract class ChunkGenerator { + + @Nullable + public Pair> findNearestMapStructure(ServerLevel world, HolderSet structures, BlockPos center, int radius, boolean skipReferencedStructures) { ++ // Paper start - StructuresLocateEvent ++ final org.bukkit.World bukkitWorld = world.getWorld(); ++ final org.bukkit.Location origin = io.papermc.paper.util.MCUtil.toLocation(world, center); ++ final List apiStructures = structures.stream().map(Holder::value).map(nms -> org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(nms)).toList(); ++ if (!apiStructures.isEmpty()) { ++ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, radius, skipReferencedStructures); ++ if (!event.callEvent()) { ++ return null; ++ } ++ if (event.getResult() != null) { ++ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), world.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(event.getResult().structure()))); ++ } ++ center = io.papermc.paper.util.MCUtil.toBlockPosition(event.getOrigin()); ++ radius = event.getRadius(); ++ skipReferencedStructures = event.shouldFindUnexplored(); ++ structures = HolderSet.direct(api -> world.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(api)), event.getStructures()); ++ } ++ // Paper end + ChunkGeneratorStructureState chunkgeneratorstructurestate = world.getChunkSource().getGeneratorState(); + Map>> map = new Object2ObjectArrayMap(); + Iterator iterator = structures.iterator(); diff --git a/patches/server/0465-Add-StructuresLocateEvent.patch b/patches/server/0465-Add-StructuresLocateEvent.patch deleted file mode 100644 index 6f3d0638ff..0000000000 --- a/patches/server/0465-Add-StructuresLocateEvent.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: dfsek -Date: Wed, 16 Sep 2020 01:12:29 -0700 -Subject: [PATCH] Add StructuresLocateEvent - -Co-authored-by: Jake Potrebic - -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 0acf8b62ddb5e005f8f861558934e8afc8673725..416b1afcbab093f45900a4d55708609ba5a7de7a 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -127,6 +127,24 @@ public abstract class ChunkGenerator { - - @Nullable - public Pair> findNearestMapStructure(ServerLevel world, HolderSet structures, BlockPos center, int radius, boolean skipReferencedStructures) { -+ // Paper start - StructuresLocateEvent -+ final org.bukkit.World bukkitWorld = world.getWorld(); -+ final org.bukkit.Location origin = io.papermc.paper.util.MCUtil.toLocation(world, center); -+ final List apiStructures = structures.stream().map(Holder::value).map(nms -> org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(nms)).toList(); -+ if (!apiStructures.isEmpty()) { -+ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, radius, skipReferencedStructures); -+ if (!event.callEvent()) { -+ return null; -+ } -+ if (event.getResult() != null) { -+ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), world.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(event.getResult().structure()))); -+ } -+ center = io.papermc.paper.util.MCUtil.toBlockPosition(event.getOrigin()); -+ radius = event.getRadius(); -+ skipReferencedStructures = event.shouldFindUnexplored(); -+ structures = HolderSet.direct(api -> world.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(api)), event.getStructures()); -+ } -+ // Paper end - ChunkGeneratorStructureState chunkgeneratorstructurestate = world.getChunkSource().getGeneratorState(); - Map>> map = new Object2ObjectArrayMap(); - Iterator iterator = structures.iterator(); diff --git a/patches/server/0465-Collision-option-for-requiring-a-player-participant.patch b/patches/server/0465-Collision-option-for-requiring-a-player-participant.patch new file mode 100644 index 0000000000..5eb393d403 --- /dev/null +++ b/patches/server/0465-Collision-option-for-requiring-a-player-participant.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 14 Nov 2020 16:48:37 +0100 +Subject: [PATCH] Collision option for requiring a player participant + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 0d99d310746cc584b2d89d0c1b7083049f4d1593..7cfb97fa2cf2c0167859b7ba888299d983c280a3 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2048,6 +2048,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public void push(Entity entity) { + if (!this.isPassengerOfSameVehicle(entity)) { + if (!entity.noPhysics && !this.noPhysics) { ++ if (this.level.paperConfig().collisions.onlyPlayersCollide && !(entity instanceof ServerPlayer || this instanceof ServerPlayer)) return; // Paper - Collision option for requiring a player participant + double d0 = entity.getX() - this.getX(); + double d1 = entity.getZ() - this.getZ(); + double d2 = Mth.absMax(d0, d1); +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java +index e2bbb4b519010cbabc0796c5b2f749b4fac32bb7..8a5b3ebc875e5c71ca0d57a52e01b74cfee408b6 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java +@@ -196,6 +196,7 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable { + + @Override + public void push(Entity entity) { ++ if (!this.level().paperConfig().collisions.allowVehicleCollisions && this.level().paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper - Collision option for requiring a player participant + if (entity instanceof AbstractBoat) { + if (entity.getBoundingBox().minY < this.getBoundingBox().maxY) { + // CraftBukkit start +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 d01a588aea379c962dd63f1428f92cf2442f4d45..7e7a78ebbf128f7d29cf9eb349f25230c9c7d5d0 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java +@@ -562,6 +562,7 @@ public abstract class AbstractMinecart extends VehicleEntity { + public void push(Entity entity) { + if (!this.level().isClientSide) { + if (!entity.noPhysics && !this.noPhysics) { ++ if (!this.level().paperConfig().collisions.allowVehicleCollisions && this.level().paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper - Collision option for requiring a player participant + if (!this.hasPassenger(entity)) { + // CraftBukkit start + VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), entity.getBukkitEntity()); diff --git a/patches/server/0466-Collision-option-for-requiring-a-player-participant.patch b/patches/server/0466-Collision-option-for-requiring-a-player-participant.patch deleted file mode 100644 index 7ab28c02eb..0000000000 --- a/patches/server/0466-Collision-option-for-requiring-a-player-participant.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 14 Nov 2020 16:48:37 +0100 -Subject: [PATCH] Collision option for requiring a player participant - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 64ea966438b0ec9d029b628543177b0faa2c259d..fe7c8a3748627232508c6c9a366977345dda9ad7 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2048,6 +2048,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public void push(Entity entity) { - if (!this.isPassengerOfSameVehicle(entity)) { - if (!entity.noPhysics && !this.noPhysics) { -+ if (this.level.paperConfig().collisions.onlyPlayersCollide && !(entity instanceof ServerPlayer || this instanceof ServerPlayer)) return; // Paper - Collision option for requiring a player participant - double d0 = entity.getX() - this.getX(); - double d1 = entity.getZ() - this.getZ(); - double d2 = Mth.absMax(d0, d1); -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java -index e2bbb4b519010cbabc0796c5b2f749b4fac32bb7..8a5b3ebc875e5c71ca0d57a52e01b74cfee408b6 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java -@@ -196,6 +196,7 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable { - - @Override - public void push(Entity entity) { -+ if (!this.level().paperConfig().collisions.allowVehicleCollisions && this.level().paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper - Collision option for requiring a player participant - if (entity instanceof AbstractBoat) { - if (entity.getBoundingBox().minY < this.getBoundingBox().maxY) { - // CraftBukkit start -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 d01a588aea379c962dd63f1428f92cf2442f4d45..7e7a78ebbf128f7d29cf9eb349f25230c9c7d5d0 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -@@ -562,6 +562,7 @@ public abstract class AbstractMinecart extends VehicleEntity { - public void push(Entity entity) { - if (!this.level().isClientSide) { - if (!entity.noPhysics && !this.noPhysics) { -+ if (!this.level().paperConfig().collisions.allowVehicleCollisions && this.level().paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper - Collision option for requiring a player participant - if (!this.hasPassenger(entity)) { - // CraftBukkit start - VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), entity.getBukkitEntity()); diff --git a/patches/server/0466-Return-chat-component-with-empty-text-instead-of-thr.patch b/patches/server/0466-Return-chat-component-with-empty-text-instead-of-thr.patch new file mode 100644 index 0000000000..20c17b39c0 --- /dev/null +++ b/patches/server/0466-Return-chat-component-with-empty-text-instead-of-thr.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: CDFN +Date: Tue, 7 Jul 2020 17:53:23 +0200 +Subject: [PATCH] Return chat component with empty text instead of throwing + exception + + +diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +index 8a03f31d07e467288dd518c99f3f29bc77eac058..3b92fb173f623a05ae99c86d98f2ecdf907f58c4 100644 +--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java +@@ -93,7 +93,12 @@ public abstract class AbstractContainerMenu { + } + private Component title; + public final Component getTitle() { +- Preconditions.checkState(this.title != null, "Title not set"); ++ // Paper start - return chat component with empty text instead of throwing error ++ // Preconditions.checkState(this.title != null, "Title not set"); ++ if (this.title == null){ ++ return Component.literal(""); ++ } ++ // Paper end - return chat component with empty text instead of throwing error + return this.title; + } + public final void setTitle(Component title) { diff --git a/patches/server/0467-Make-schedule-command-per-world.patch b/patches/server/0467-Make-schedule-command-per-world.patch new file mode 100644 index 0000000000..3ac2f8e3f4 --- /dev/null +++ b/patches/server/0467-Make-schedule-command-per-world.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 4 Jan 2021 19:52:44 -0800 +Subject: [PATCH] Make schedule command per-world + + +diff --git a/src/main/java/net/minecraft/server/commands/ScheduleCommand.java b/src/main/java/net/minecraft/server/commands/ScheduleCommand.java +index 10b059a93762d9711fb4aedff572edfaebcb8264..1090759025969c04267de8b96ad045b1da0cb246 100644 +--- a/src/main/java/net/minecraft/server/commands/ScheduleCommand.java ++++ b/src/main/java/net/minecraft/server/commands/ScheduleCommand.java +@@ -33,7 +33,7 @@ public class ScheduleCommand { + }); + private static final SimpleCommandExceptionType ERROR_MACRO = new SimpleCommandExceptionType(Component.translatableEscape("commands.schedule.macro")); + private static final SuggestionProvider SUGGEST_SCHEDULE = (commandcontext, suggestionsbuilder) -> { +- return SharedSuggestionProvider.suggest((Iterable) ((CommandSourceStack) commandcontext.getSource()).getServer().getWorldData().overworldData().getScheduledEvents().getEventsIds(), suggestionsbuilder); ++ return SharedSuggestionProvider.suggest((Iterable) ((net.minecraft.commands.CommandSourceStack) commandcontext.getSource()).getLevel().serverLevelData.getScheduledEvents().getEventsIds(), suggestionsbuilder); // Paper - Make schedule command per-world + }; + + public ScheduleCommand() {} +@@ -93,7 +93,7 @@ public class ScheduleCommand { + } + + private static int remove(CommandSourceStack source, String eventName) throws CommandSyntaxException { +- int i = source.getServer().getWorldData().overworldData().getScheduledEvents().remove(eventName); ++ int i = source.getLevel().serverLevelData.getScheduledEvents().remove(eventName); // Paper - Make schedule command per-world + + if (i == 0) { + throw ScheduleCommand.ERROR_CANT_REMOVE.create(eventName); diff --git a/patches/server/0467-Return-chat-component-with-empty-text-instead-of-thr.patch b/patches/server/0467-Return-chat-component-with-empty-text-instead-of-thr.patch deleted file mode 100644 index 20c17b39c0..0000000000 --- a/patches/server/0467-Return-chat-component-with-empty-text-instead-of-thr.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: CDFN -Date: Tue, 7 Jul 2020 17:53:23 +0200 -Subject: [PATCH] Return chat component with empty text instead of throwing - exception - - -diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -index 8a03f31d07e467288dd518c99f3f29bc77eac058..3b92fb173f623a05ae99c86d98f2ecdf907f58c4 100644 ---- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -93,7 +93,12 @@ public abstract class AbstractContainerMenu { - } - private Component title; - public final Component getTitle() { -- Preconditions.checkState(this.title != null, "Title not set"); -+ // Paper start - return chat component with empty text instead of throwing error -+ // Preconditions.checkState(this.title != null, "Title not set"); -+ if (this.title == null){ -+ return Component.literal(""); -+ } -+ // Paper end - return chat component with empty text instead of throwing error - return this.title; - } - public final void setTitle(Component title) { diff --git a/patches/server/0468-Configurable-max-leash-distance.patch b/patches/server/0468-Configurable-max-leash-distance.patch new file mode 100644 index 0000000000..39054ac60f --- /dev/null +++ b/patches/server/0468-Configurable-max-leash-distance.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 3 Jan 2021 21:04:03 -0800 +Subject: [PATCH] Configurable max leash distance + + +diff --git a/src/main/java/net/minecraft/world/entity/Leashable.java b/src/main/java/net/minecraft/world/entity/Leashable.java +index 4692704b58d1b73a45f1d587782dc706da94a6e6..5e67402340a81a965b0b3af88307d36500c2dc6b 100644 +--- a/src/main/java/net/minecraft/world/entity/Leashable.java ++++ b/src/main/java/net/minecraft/world/entity/Leashable.java +@@ -201,7 +201,7 @@ public interface Leashable { + return; + } + +- if ((double) f > 10.0D) { ++ if ((double) f > entity.level().paperConfig().misc.maxLeashDistance.or(LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance + ((Leashable) entity).leashTooFarBehaviour(); + } else if ((double) f > 6.0D) { + ((Leashable) entity).elasticRangeLeashBehaviour(entity1, f); +diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +index 144ef3cc71bb265646e48f3a5f10d971b5768154..9c6e2124da7c2358d2d524c52d3e77422f15f6e5 100644 +--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +@@ -101,7 +101,7 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { + @Override + public boolean handleLeashAtDistance(Entity leashHolder, float distance) { + if (this.isInSittingPose()) { +- if (distance > 10.0F) { ++ if (distance > (float) this.level().paperConfig().misc.maxLeashDistance.or(Leashable.LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance + this.dropLeash(); + } + diff --git a/patches/server/0468-Make-schedule-command-per-world.patch b/patches/server/0468-Make-schedule-command-per-world.patch deleted file mode 100644 index 3ac2f8e3f4..0000000000 --- a/patches/server/0468-Make-schedule-command-per-world.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 4 Jan 2021 19:52:44 -0800 -Subject: [PATCH] Make schedule command per-world - - -diff --git a/src/main/java/net/minecraft/server/commands/ScheduleCommand.java b/src/main/java/net/minecraft/server/commands/ScheduleCommand.java -index 10b059a93762d9711fb4aedff572edfaebcb8264..1090759025969c04267de8b96ad045b1da0cb246 100644 ---- a/src/main/java/net/minecraft/server/commands/ScheduleCommand.java -+++ b/src/main/java/net/minecraft/server/commands/ScheduleCommand.java -@@ -33,7 +33,7 @@ public class ScheduleCommand { - }); - private static final SimpleCommandExceptionType ERROR_MACRO = new SimpleCommandExceptionType(Component.translatableEscape("commands.schedule.macro")); - private static final SuggestionProvider SUGGEST_SCHEDULE = (commandcontext, suggestionsbuilder) -> { -- return SharedSuggestionProvider.suggest((Iterable) ((CommandSourceStack) commandcontext.getSource()).getServer().getWorldData().overworldData().getScheduledEvents().getEventsIds(), suggestionsbuilder); -+ return SharedSuggestionProvider.suggest((Iterable) ((net.minecraft.commands.CommandSourceStack) commandcontext.getSource()).getLevel().serverLevelData.getScheduledEvents().getEventsIds(), suggestionsbuilder); // Paper - Make schedule command per-world - }; - - public ScheduleCommand() {} -@@ -93,7 +93,7 @@ public class ScheduleCommand { - } - - private static int remove(CommandSourceStack source, String eventName) throws CommandSyntaxException { -- int i = source.getServer().getWorldData().overworldData().getScheduledEvents().remove(eventName); -+ int i = source.getLevel().serverLevelData.getScheduledEvents().remove(eventName); // Paper - Make schedule command per-world - - if (i == 0) { - throw ScheduleCommand.ERROR_CANT_REMOVE.create(eventName); diff --git a/patches/server/0469-Add-BlockPreDispenseEvent.patch b/patches/server/0469-Add-BlockPreDispenseEvent.patch new file mode 100644 index 0000000000..f2725046a1 --- /dev/null +++ b/patches/server/0469-Add-BlockPreDispenseEvent.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Madeline Miller +Date: Sun, 17 Jan 2021 13:16:09 +1000 +Subject: [PATCH] Add BlockPreDispenseEvent + + +diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java +index d915ef1030728a3f6ff303977784097b712238d4..6a8e0df7d0150ad8dbbffcd5f49c4623a259e680 100644 +--- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java +@@ -107,6 +107,7 @@ public class DispenserBlock extends BaseEntityBlock { + DispenseItemBehavior idispensebehavior = this.getDispenseMethod(world, itemstack); + + if (idispensebehavior != DispenseItemBehavior.NOOP) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent + DispenserBlock.eventFired = false; // CraftBukkit - reset event status + tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack)); + } +diff --git a/src/main/java/net/minecraft/world/level/block/DropperBlock.java b/src/main/java/net/minecraft/world/level/block/DropperBlock.java +index 91b514967405115f22edf4255775361a672e5c2f..ddecf443df3679e3098eb54edd19585a0512e342 100644 +--- a/src/main/java/net/minecraft/world/level/block/DropperBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DropperBlock.java +@@ -71,6 +71,7 @@ public class DropperBlock extends DispenserBlock { + ItemStack itemstack1; + + if (iinventory == null) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent + itemstack1 = DropperBlock.DISPENSE_BEHAVIOUR.dispense(sourceblock, itemstack); + } else { + // CraftBukkit start - Fire event when pushing items into other inventories +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 696867479e74c3c94e4131f2bbb97c857ed5e9dd..6d1d3451054af05e2381d70d71b99869f37c0901 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -2132,5 +2132,11 @@ public class CraftEventFactory { + io.papermc.paper.event.block.BlockFailedDispenseEvent event = new io.papermc.paper.event.block.BlockFailedDispenseEvent(block); + return event.callEvent(); + } ++ ++ public static boolean handleBlockPreDispenseEvent(ServerLevel serverLevel, BlockPos pos, ItemStack itemStack, int slot) { ++ org.bukkit.block.Block block = CraftBlock.at(serverLevel, pos); ++ io.papermc.paper.event.block.BlockPreDispenseEvent event = new io.papermc.paper.event.block.BlockPreDispenseEvent(block, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), slot); ++ return event.callEvent(); ++ } + // Paper end + } diff --git a/patches/server/0469-Configurable-max-leash-distance.patch b/patches/server/0469-Configurable-max-leash-distance.patch deleted file mode 100644 index 39054ac60f..0000000000 --- a/patches/server/0469-Configurable-max-leash-distance.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 3 Jan 2021 21:04:03 -0800 -Subject: [PATCH] Configurable max leash distance - - -diff --git a/src/main/java/net/minecraft/world/entity/Leashable.java b/src/main/java/net/minecraft/world/entity/Leashable.java -index 4692704b58d1b73a45f1d587782dc706da94a6e6..5e67402340a81a965b0b3af88307d36500c2dc6b 100644 ---- a/src/main/java/net/minecraft/world/entity/Leashable.java -+++ b/src/main/java/net/minecraft/world/entity/Leashable.java -@@ -201,7 +201,7 @@ public interface Leashable { - return; - } - -- if ((double) f > 10.0D) { -+ if ((double) f > entity.level().paperConfig().misc.maxLeashDistance.or(LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance - ((Leashable) entity).leashTooFarBehaviour(); - } else if ((double) f > 6.0D) { - ((Leashable) entity).elasticRangeLeashBehaviour(entity1, f); -diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -index 144ef3cc71bb265646e48f3a5f10d971b5768154..9c6e2124da7c2358d2d524c52d3e77422f15f6e5 100644 ---- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -@@ -101,7 +101,7 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { - @Override - public boolean handleLeashAtDistance(Entity leashHolder, float distance) { - if (this.isInSittingPose()) { -- if (distance > 10.0F) { -+ if (distance > (float) this.level().paperConfig().misc.maxLeashDistance.or(Leashable.LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance - this.dropLeash(); - } - diff --git a/patches/server/0470-Add-BlockPreDispenseEvent.patch b/patches/server/0470-Add-BlockPreDispenseEvent.patch deleted file mode 100644 index f2725046a1..0000000000 --- a/patches/server/0470-Add-BlockPreDispenseEvent.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Madeline Miller -Date: Sun, 17 Jan 2021 13:16:09 +1000 -Subject: [PATCH] Add BlockPreDispenseEvent - - -diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -index d915ef1030728a3f6ff303977784097b712238d4..6a8e0df7d0150ad8dbbffcd5f49c4623a259e680 100644 ---- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -@@ -107,6 +107,7 @@ public class DispenserBlock extends BaseEntityBlock { - DispenseItemBehavior idispensebehavior = this.getDispenseMethod(world, itemstack); - - if (idispensebehavior != DispenseItemBehavior.NOOP) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent - DispenserBlock.eventFired = false; // CraftBukkit - reset event status - tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack)); - } -diff --git a/src/main/java/net/minecraft/world/level/block/DropperBlock.java b/src/main/java/net/minecraft/world/level/block/DropperBlock.java -index 91b514967405115f22edf4255775361a672e5c2f..ddecf443df3679e3098eb54edd19585a0512e342 100644 ---- a/src/main/java/net/minecraft/world/level/block/DropperBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DropperBlock.java -@@ -71,6 +71,7 @@ public class DropperBlock extends DispenserBlock { - ItemStack itemstack1; - - if (iinventory == null) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent - itemstack1 = DropperBlock.DISPENSE_BEHAVIOUR.dispense(sourceblock, itemstack); - } else { - // CraftBukkit start - Fire event when pushing items into other inventories -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 696867479e74c3c94e4131f2bbb97c857ed5e9dd..6d1d3451054af05e2381d70d71b99869f37c0901 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -2132,5 +2132,11 @@ public class CraftEventFactory { - io.papermc.paper.event.block.BlockFailedDispenseEvent event = new io.papermc.paper.event.block.BlockFailedDispenseEvent(block); - return event.callEvent(); - } -+ -+ public static boolean handleBlockPreDispenseEvent(ServerLevel serverLevel, BlockPos pos, ItemStack itemStack, int slot) { -+ org.bukkit.block.Block block = CraftBlock.at(serverLevel, pos); -+ io.papermc.paper.event.block.BlockPreDispenseEvent event = new io.papermc.paper.event.block.BlockPreDispenseEvent(block, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), slot); -+ return event.callEvent(); -+ } - // Paper end - } diff --git a/patches/server/0470-Add-PlayerChangeBeaconEffectEvent.patch b/patches/server/0470-Add-PlayerChangeBeaconEffectEvent.patch new file mode 100644 index 0000000000..f8164b3839 --- /dev/null +++ b/patches/server/0470-Add-PlayerChangeBeaconEffectEvent.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 24 Jun 2020 15:14:51 -0600 +Subject: [PATCH] Add PlayerChangeBeaconEffectEvent + + +diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java +index cb063d6e7f4d34eab3a5f52b11f671e0c99bbd40..c257660c79516a5919032b771fc3ac9575e9db9d 100644 +--- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java +@@ -157,12 +157,25 @@ public class BeaconMenu extends AbstractContainerMenu { + return BeaconMenu.decodeEffect(this.beaconData.get(2)); + } + ++ // Paper start - Add PlayerChangeBeaconEffectEvent ++ private static @Nullable org.bukkit.potion.PotionEffectType convert(Optional> optionalEffect) { ++ return optionalEffect.map(org.bukkit.craftbukkit.potion.CraftPotionEffectType::minecraftHolderToBukkit).orElse(null); ++ } ++ // Paper end - Add PlayerChangeBeaconEffectEvent ++ + public void updateEffects(Optional> primary, Optional> secondary) { + if (this.paymentSlot.hasItem()) { +- this.beaconData.set(1, BeaconMenu.encodeEffect((Holder) primary.orElse(null)));// CraftBukkit - decompile error +- this.beaconData.set(2, BeaconMenu.encodeEffect((Holder) secondary.orElse(null)));// CraftBukkit - decompile error ++ // 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()); ++ if (event.callEvent()) { ++ // Paper end - Add PlayerChangeBeaconEffectEvent ++ this.beaconData.set(1, BeaconMenu.encodeEffect(event.getPrimary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getPrimary())));// CraftBukkit - decompile error ++ this.beaconData.set(2, BeaconMenu.encodeEffect(event.getSecondary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getSecondary())));// CraftBukkit - decompile error ++ if (event.willConsumeItem()) { // Paper + this.paymentSlot.remove(1); ++ } // Paper + this.access.execute(Level::blockEntityChanged); ++ } // Paper end - Add PlayerChangeBeaconEffectEvent + } + + } diff --git a/patches/server/0471-Add-PlayerChangeBeaconEffectEvent.patch b/patches/server/0471-Add-PlayerChangeBeaconEffectEvent.patch deleted file mode 100644 index f8164b3839..0000000000 --- a/patches/server/0471-Add-PlayerChangeBeaconEffectEvent.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 24 Jun 2020 15:14:51 -0600 -Subject: [PATCH] Add PlayerChangeBeaconEffectEvent - - -diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -index cb063d6e7f4d34eab3a5f52b11f671e0c99bbd40..c257660c79516a5919032b771fc3ac9575e9db9d 100644 ---- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java -@@ -157,12 +157,25 @@ public class BeaconMenu extends AbstractContainerMenu { - return BeaconMenu.decodeEffect(this.beaconData.get(2)); - } - -+ // Paper start - Add PlayerChangeBeaconEffectEvent -+ private static @Nullable org.bukkit.potion.PotionEffectType convert(Optional> optionalEffect) { -+ return optionalEffect.map(org.bukkit.craftbukkit.potion.CraftPotionEffectType::minecraftHolderToBukkit).orElse(null); -+ } -+ // Paper end - Add PlayerChangeBeaconEffectEvent -+ - public void updateEffects(Optional> primary, Optional> secondary) { - if (this.paymentSlot.hasItem()) { -- this.beaconData.set(1, BeaconMenu.encodeEffect((Holder) primary.orElse(null)));// CraftBukkit - decompile error -- this.beaconData.set(2, BeaconMenu.encodeEffect((Holder) secondary.orElse(null)));// CraftBukkit - decompile error -+ // 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()); -+ if (event.callEvent()) { -+ // Paper end - Add PlayerChangeBeaconEffectEvent -+ this.beaconData.set(1, BeaconMenu.encodeEffect(event.getPrimary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getPrimary())));// CraftBukkit - decompile error -+ this.beaconData.set(2, BeaconMenu.encodeEffect(event.getSecondary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getSecondary())));// CraftBukkit - decompile error -+ if (event.willConsumeItem()) { // Paper - this.paymentSlot.remove(1); -+ } // Paper - this.access.execute(Level::blockEntityChanged); -+ } // Paper end - Add PlayerChangeBeaconEffectEvent - } - - } diff --git a/patches/server/0471-Add-toggle-for-always-placing-the-dragon-egg.patch b/patches/server/0471-Add-toggle-for-always-placing-the-dragon-egg.patch new file mode 100644 index 0000000000..0b28271dd1 --- /dev/null +++ b/patches/server/0471-Add-toggle-for-always-placing-the-dragon-egg.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 26 Nov 2020 11:47:24 +0000 +Subject: [PATCH] Add toggle for always placing the dragon egg + + +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 323fbf684b7062c1b9084f1718538a3b3414d5bf..0e1eceb2b83aaafccbb5d58cf5098cfbc6f25a54 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 +@@ -410,7 +410,7 @@ public class EndDragonFight { + this.dragonEvent.setVisible(false); + this.spawnExitPortal(true); + this.spawnNewGateway(); +- if (!this.previouslyKilled) { ++ if (this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - Add toggle for always placing the dragon egg + this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState()); + } + diff --git a/patches/server/0472-Add-PlayerStonecutterRecipeSelectEvent.patch b/patches/server/0472-Add-PlayerStonecutterRecipeSelectEvent.patch new file mode 100644 index 0000000000..66c297aace --- /dev/null +++ b/patches/server/0472-Add-PlayerStonecutterRecipeSelectEvent.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 27 Nov 2020 17:14:27 -0800 +Subject: [PATCH] Add PlayerStonecutterRecipeSelectEvent + +Co-Authored-By: MiniDigger + +diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java +index 46d6bc61ba54ab23eb35915073cfd5a3ab0111f1..74ea3f0154733ed4f096d88403fe011cca663e02 100644 +--- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java +@@ -64,7 +64,7 @@ public class StonecutterMenu extends AbstractContainerMenu { + + public StonecutterMenu(int syncId, Inventory playerInventory, final ContainerLevelAccess context) { + super(MenuType.STONECUTTER, syncId); +- this.selectedRecipeIndex = DataSlot.standalone(); ++ this.selectedRecipeIndex = DataSlot.shared(new int[1], 0); // Paper - Add PlayerStonecutterRecipeSelectEvent + this.recipesForInput = SelectableRecipe.SingleInputSet.empty(); + this.input = ItemStack.EMPTY; + this.slotUpdateListener = () -> { +@@ -153,8 +153,34 @@ public class StonecutterMenu extends AbstractContainerMenu { + return false; + } else { + if (this.isValidRecipeIndex(id)) { +- this.selectedRecipeIndex.set(id); +- this.setupResultSlot(id); ++ // Paper start - Add PlayerStonecutterRecipeSelectEvent ++ int recipeIndex = id; ++ this.selectedRecipeIndex.set(recipeIndex); ++ this.selectedRecipeIndex.checkAndClearUpdateFlag(); // mark as changed ++ paperEventBlock: if (this.isValidRecipeIndex(id)) { ++ final Optional> recipe = this.recipesForInput.entries().get(id).recipe().recipe(); ++ if (recipe.isEmpty()) break paperEventBlock; // The recipe selected does not have an actual server recipe (presumably its the empty one). Cannot call the event, just break. ++ ++ io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent event = new io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent((Player) player.getBukkitEntity(), getBukkitView().getTopInventory(), (org.bukkit.inventory.StonecuttingRecipe) recipe.get().toBukkitRecipe()); ++ if (!event.callEvent()) { ++ player.containerMenu.sendAllDataToRemote(); ++ return false; ++ } ++ ++ net.minecraft.resources.ResourceLocation key = org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getStonecuttingRecipe().getKey()); ++ if (!recipe.get().id().location().equals(key)) { // If the recipe did NOT stay the same ++ for (int newRecipeIndex = 0; newRecipeIndex < this.recipesForInput.entries().size(); newRecipeIndex++) { ++ if (this.recipesForInput.entries().get(newRecipeIndex).recipe().recipe().filter(r -> r.id().location().equals(key)).isPresent()) { ++ recipeIndex = newRecipeIndex; ++ break; ++ } ++ } ++ } ++ } ++ player.containerMenu.sendAllDataToRemote(); ++ this.selectedRecipeIndex.set(recipeIndex); // set new index, so that listeners can read it ++ this.setupResultSlot(recipeIndex); ++ // Paper end - Add PlayerStonecutterRecipeSelectEvent + } + + return true; diff --git a/patches/server/0472-Add-toggle-for-always-placing-the-dragon-egg.patch b/patches/server/0472-Add-toggle-for-always-placing-the-dragon-egg.patch deleted file mode 100644 index 0b28271dd1..0000000000 --- a/patches/server/0472-Add-toggle-for-always-placing-the-dragon-egg.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 26 Nov 2020 11:47:24 +0000 -Subject: [PATCH] Add toggle for always placing the dragon egg - - -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 323fbf684b7062c1b9084f1718538a3b3414d5bf..0e1eceb2b83aaafccbb5d58cf5098cfbc6f25a54 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 -@@ -410,7 +410,7 @@ public class EndDragonFight { - this.dragonEvent.setVisible(false); - this.spawnExitPortal(true); - this.spawnNewGateway(); -- if (!this.previouslyKilled) { -+ if (this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - Add toggle for always placing the dragon egg - this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState()); - } - diff --git a/patches/server/0473-Add-PlayerStonecutterRecipeSelectEvent.patch b/patches/server/0473-Add-PlayerStonecutterRecipeSelectEvent.patch deleted file mode 100644 index 66c297aace..0000000000 --- a/patches/server/0473-Add-PlayerStonecutterRecipeSelectEvent.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 27 Nov 2020 17:14:27 -0800 -Subject: [PATCH] Add PlayerStonecutterRecipeSelectEvent - -Co-Authored-By: MiniDigger - -diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java -index 46d6bc61ba54ab23eb35915073cfd5a3ab0111f1..74ea3f0154733ed4f096d88403fe011cca663e02 100644 ---- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java -@@ -64,7 +64,7 @@ public class StonecutterMenu extends AbstractContainerMenu { - - public StonecutterMenu(int syncId, Inventory playerInventory, final ContainerLevelAccess context) { - super(MenuType.STONECUTTER, syncId); -- this.selectedRecipeIndex = DataSlot.standalone(); -+ this.selectedRecipeIndex = DataSlot.shared(new int[1], 0); // Paper - Add PlayerStonecutterRecipeSelectEvent - this.recipesForInput = SelectableRecipe.SingleInputSet.empty(); - this.input = ItemStack.EMPTY; - this.slotUpdateListener = () -> { -@@ -153,8 +153,34 @@ public class StonecutterMenu extends AbstractContainerMenu { - return false; - } else { - if (this.isValidRecipeIndex(id)) { -- this.selectedRecipeIndex.set(id); -- this.setupResultSlot(id); -+ // Paper start - Add PlayerStonecutterRecipeSelectEvent -+ int recipeIndex = id; -+ this.selectedRecipeIndex.set(recipeIndex); -+ this.selectedRecipeIndex.checkAndClearUpdateFlag(); // mark as changed -+ paperEventBlock: if (this.isValidRecipeIndex(id)) { -+ final Optional> recipe = this.recipesForInput.entries().get(id).recipe().recipe(); -+ if (recipe.isEmpty()) break paperEventBlock; // The recipe selected does not have an actual server recipe (presumably its the empty one). Cannot call the event, just break. -+ -+ io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent event = new io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent((Player) player.getBukkitEntity(), getBukkitView().getTopInventory(), (org.bukkit.inventory.StonecuttingRecipe) recipe.get().toBukkitRecipe()); -+ if (!event.callEvent()) { -+ player.containerMenu.sendAllDataToRemote(); -+ return false; -+ } -+ -+ net.minecraft.resources.ResourceLocation key = org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getStonecuttingRecipe().getKey()); -+ if (!recipe.get().id().location().equals(key)) { // If the recipe did NOT stay the same -+ for (int newRecipeIndex = 0; newRecipeIndex < this.recipesForInput.entries().size(); newRecipeIndex++) { -+ if (this.recipesForInput.entries().get(newRecipeIndex).recipe().recipe().filter(r -> r.id().location().equals(key)).isPresent()) { -+ recipeIndex = newRecipeIndex; -+ break; -+ } -+ } -+ } -+ } -+ player.containerMenu.sendAllDataToRemote(); -+ this.selectedRecipeIndex.set(recipeIndex); // set new index, so that listeners can read it -+ this.setupResultSlot(recipeIndex); -+ // Paper end - Add PlayerStonecutterRecipeSelectEvent - } - - return true; diff --git a/patches/server/0473-Expand-EntityUnleashEvent.patch b/patches/server/0473-Expand-EntityUnleashEvent.patch new file mode 100644 index 0000000000..ffe8078715 --- /dev/null +++ b/patches/server/0473-Expand-EntityUnleashEvent.patch @@ -0,0 +1,174 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Fri, 29 Jan 2021 15:13:11 +0100 +Subject: [PATCH] Expand EntityUnleashEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 7cfb97fa2cf2c0167859b7ba888299d983c280a3..a3dab1d471e2ac876758d73c7b418a179349a97f 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2715,12 +2715,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + if (leashable.getLeashHolder() == player) { + if (!this.level().isClientSide()) { + // CraftBukkit start - fire PlayerUnleashEntityEvent +- if (CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand).isCancelled()) { ++ // Paper start - Expand EntityUnleashEvent ++ org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand, !player.hasInfiniteMaterials()); ++ if (event.isCancelled()) { ++ // Paper end - Expand EntityUnleashEvent + ((ServerPlayer) player).connection.send(new ClientboundSetEntityLinkPacket(this, leashable.getLeashHolder())); + return InteractionResult.PASS; + } + // CraftBukkit end +- if (player.hasInfiniteMaterials()) { ++ if (!event.isDropLeash()) { // Paper - Expand EntityUnleashEvent + leashable.removeLeash(); + } else { + leashable.dropLeash(); +@@ -3690,9 +3693,16 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + + protected void removeAfterChangingDimensions() { + this.setRemoved(Entity.RemovalReason.CHANGED_DIMENSION, null); // CraftBukkit - add Bukkit remove cause +- if (this instanceof Leashable leashable) { +- this.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN)); // CraftBukkit +- leashable.removeLeash(); ++ if (this instanceof Leashable leashable && leashable.isLeashed()) { // Paper - only call if it is leashed ++ // Paper start - Expand EntityUnleashEvent ++ final EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN, false); // CraftBukkit ++ event.callEvent(); ++ if (!event.isDropLeash()) { ++ leashable.removeLeash(); ++ } else { ++ leashable.dropLeash(); ++ } ++ // Paper end - Expand EntityUnleashEvent + } + + } +diff --git a/src/main/java/net/minecraft/world/entity/Leashable.java b/src/main/java/net/minecraft/world/entity/Leashable.java +index 5e67402340a81a965b0b3af88307d36500c2dc6b..68b869c5d76aeb390a05b053eef70486bd4126fd 100644 +--- a/src/main/java/net/minecraft/world/entity/Leashable.java ++++ b/src/main/java/net/minecraft/world/entity/Leashable.java +@@ -184,8 +184,11 @@ public interface Leashable { + + if (leashable_a != null && leashable_a.leashHolder != null) { + if (!entity.isAlive() || !leashable_a.leashHolder.isAlive()) { +- world.getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(entity.getBukkitEntity(), (!entity.isAlive()) ? UnleashReason.PLAYER_UNLEASH : UnleashReason.HOLDER_GONE)); // CraftBukkit +- if (world.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS) && !entity.pluginRemoved) { // CraftBukkit - SPIGOT-7487: Don't drop leash, when the holder was removed by a plugin ++ // Paper start - Expand EntityUnleashEvent ++ final EntityUnleashEvent event = new EntityUnleashEvent(entity.getBukkitEntity(), (!entity.isAlive()) ? UnleashReason.PLAYER_UNLEASH : UnleashReason.HOLDER_GONE, world.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS) && !entity.pluginRemoved); ++ event.callEvent(); ++ if (event.isDropLeash()) { // CraftBukkit - SPIGOT-7487: Don't drop leash, when the holder was removed by a plugin ++ // Paper end - Expand EntityUnleashEvent + ((Leashable) entity).dropLeash(); + } else { + ((Leashable) entity).removeLeash(); +@@ -220,11 +223,20 @@ public interface Leashable { + + default void leashTooFarBehaviour() { + // CraftBukkit start ++ boolean dropLeash = true; // Paper + if (this instanceof Entity entity) { +- entity.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(entity.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE)); ++ // Paper start - Expand EntityUnleashEvent ++ final EntityUnleashEvent event = new EntityUnleashEvent(entity.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE, true); ++ if (!event.callEvent()) return; ++ dropLeash = event.isDropLeash(); + } + // CraftBukkit end +- this.dropLeash(); ++ if (dropLeash) { ++ this.dropLeash(); ++ } else { ++ this.removeLeash(); ++ } ++ // Paper end - Expand EntityUnleashEvent + } + + default void closeRangeLeashBehaviour(Entity entity) {} +diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java +index b3c27cdf7d336404403fe09553080835f2d3de49..7d3e165bae2c00737019689b7bf1e74ad2517270 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -1612,8 +1612,15 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + boolean flag1 = super.startRiding(entity, force); + + if (flag1 && this.isLeashed()) { +- this.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN)); // CraftBukkit +- this.dropLeash(); ++ // Paper start - Expand EntityUnleashEvent ++ EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.UNKNOWN, true); ++ if (!event.callEvent()) { return flag1; } ++ if (event.isDropLeash()) { ++ this.dropLeash(); ++ } else { ++ this.removeLeash(); ++ } ++ // Paper end - Expand EntityUnleashEvent + } + + return flag1; +diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +index 9c6e2124da7c2358d2d524c52d3e77422f15f6e5..45a340fddcec48dfb796f4515a500452adb30c59 100644 +--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +@@ -102,7 +102,15 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { + public boolean handleLeashAtDistance(Entity leashHolder, float distance) { + if (this.isInSittingPose()) { + if (distance > (float) this.level().paperConfig().misc.maxLeashDistance.or(Leashable.LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance +- this.dropLeash(); ++ // Paper start - Expand EntityUnleashEvent ++ org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(this.getBukkitEntity(), org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.DISTANCE, true); ++ if (!event.callEvent()) return false; ++ if (event.isDropLeash()) { ++ this.dropLeash(); ++ } else { ++ this.removeLeash(); ++ } ++ // Paper end - Expand EntityUnleashEvent + } + + return false; +diff --git a/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java b/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java +index d4955d4174e5c2920d5cccaa4494db2c27284660..d06ec03ad16630f2dfd81cf9f32542bd1c2592de 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java +@@ -119,13 +119,18 @@ public class LeashFenceKnotEntity extends BlockAttachedEntity { + + if (leashable1.isLeashed() && leashable1.getLeashHolder() == this) { + // CraftBukkit start ++ boolean dropLeash = !player.hasInfiniteMaterials(); + if (leashable1 instanceof Entity leashed) { +- if (CraftEventFactory.callPlayerUnleashEntityEvent(leashed, player, hand).isCancelled()) { ++ // Paper start - Expand EntityUnleashEvent ++ org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(leashed, player, hand, dropLeash); ++ dropLeash = event.isDropLeash(); ++ if (event.isCancelled()) { ++ // Paper end - Expand EntityUnleashEvent + die = false; + continue; + } + } +- if (player.getAbilities().instabuild){ ++ if (!dropLeash) { // Paper - Expand EntityUnleashEvent + leashable1.removeLeash(); + } else { + leashable1.dropLeash(); +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 6d1d3451054af05e2381d70d71b99869f37c0901..697c69b60aa45b6a229f3bec77dc728e50a895ce 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1596,8 +1596,10 @@ public class CraftEventFactory { + Bukkit.getPluginManager().callEvent(new PlayerRecipeBookSettingsChangeEvent(player.getBukkitEntity(), bukkitType, open, filter)); + } + +- public static PlayerUnleashEntityEvent callPlayerUnleashEntityEvent(Entity entity, net.minecraft.world.entity.player.Player player, InteractionHand enumhand) { +- PlayerUnleashEntityEvent event = new PlayerUnleashEntityEvent(entity.getBukkitEntity(), (Player) player.getBukkitEntity(), CraftEquipmentSlot.getHand(enumhand)); ++ // Paper start - Expand EntityUnleashEvent ++ public static PlayerUnleashEntityEvent callPlayerUnleashEntityEvent(Entity entity, net.minecraft.world.entity.player.Player player, InteractionHand enumhand, boolean dropLeash) { ++ PlayerUnleashEntityEvent event = new PlayerUnleashEntityEvent(entity.getBukkitEntity(), (Player) player.getBukkitEntity(), CraftEquipmentSlot.getHand(enumhand), dropLeash); ++ // Paper end - Expand EntityUnleashEvent + entity.level().getCraftServer().getPluginManager().callEvent(event); + return event; + } diff --git a/patches/server/0474-Expand-EntityUnleashEvent.patch b/patches/server/0474-Expand-EntityUnleashEvent.patch deleted file mode 100644 index 41da32df15..0000000000 --- a/patches/server/0474-Expand-EntityUnleashEvent.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Fri, 29 Jan 2021 15:13:11 +0100 -Subject: [PATCH] Expand EntityUnleashEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index fe7c8a3748627232508c6c9a366977345dda9ad7..627946dba408cea922614497c0c1b2b48a429f06 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2715,12 +2715,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (leashable.getLeashHolder() == player) { - if (!this.level().isClientSide()) { - // CraftBukkit start - fire PlayerUnleashEntityEvent -- if (CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand).isCancelled()) { -+ // Paper start - Expand EntityUnleashEvent -+ org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand, !player.hasInfiniteMaterials()); -+ if (event.isCancelled()) { -+ // Paper end - Expand EntityUnleashEvent - ((ServerPlayer) player).connection.send(new ClientboundSetEntityLinkPacket(this, leashable.getLeashHolder())); - return InteractionResult.PASS; - } - // CraftBukkit end -- if (player.hasInfiniteMaterials()) { -+ if (!event.isDropLeash()) { // Paper - Expand EntityUnleashEvent - leashable.removeLeash(); - } else { - leashable.dropLeash(); -@@ -3690,9 +3693,16 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - - protected void removeAfterChangingDimensions() { - this.setRemoved(Entity.RemovalReason.CHANGED_DIMENSION, null); // CraftBukkit - add Bukkit remove cause -- if (this instanceof Leashable leashable) { -- this.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN)); // CraftBukkit -- leashable.removeLeash(); -+ if (this instanceof Leashable leashable && leashable.isLeashed()) { // Paper - only call if it is leashed -+ // Paper start - Expand EntityUnleashEvent -+ final EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN, false); // CraftBukkit -+ event.callEvent(); -+ if (!event.isDropLeash()) { -+ leashable.removeLeash(); -+ } else { -+ leashable.dropLeash(); -+ } -+ // Paper end - Expand EntityUnleashEvent - } - - } -diff --git a/src/main/java/net/minecraft/world/entity/Leashable.java b/src/main/java/net/minecraft/world/entity/Leashable.java -index 5e67402340a81a965b0b3af88307d36500c2dc6b..68b869c5d76aeb390a05b053eef70486bd4126fd 100644 ---- a/src/main/java/net/minecraft/world/entity/Leashable.java -+++ b/src/main/java/net/minecraft/world/entity/Leashable.java -@@ -184,8 +184,11 @@ public interface Leashable { - - if (leashable_a != null && leashable_a.leashHolder != null) { - if (!entity.isAlive() || !leashable_a.leashHolder.isAlive()) { -- world.getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(entity.getBukkitEntity(), (!entity.isAlive()) ? UnleashReason.PLAYER_UNLEASH : UnleashReason.HOLDER_GONE)); // CraftBukkit -- if (world.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS) && !entity.pluginRemoved) { // CraftBukkit - SPIGOT-7487: Don't drop leash, when the holder was removed by a plugin -+ // Paper start - Expand EntityUnleashEvent -+ final EntityUnleashEvent event = new EntityUnleashEvent(entity.getBukkitEntity(), (!entity.isAlive()) ? UnleashReason.PLAYER_UNLEASH : UnleashReason.HOLDER_GONE, world.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS) && !entity.pluginRemoved); -+ event.callEvent(); -+ if (event.isDropLeash()) { // CraftBukkit - SPIGOT-7487: Don't drop leash, when the holder was removed by a plugin -+ // Paper end - Expand EntityUnleashEvent - ((Leashable) entity).dropLeash(); - } else { - ((Leashable) entity).removeLeash(); -@@ -220,11 +223,20 @@ public interface Leashable { - - default void leashTooFarBehaviour() { - // CraftBukkit start -+ boolean dropLeash = true; // Paper - if (this instanceof Entity entity) { -- entity.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(entity.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE)); -+ // Paper start - Expand EntityUnleashEvent -+ final EntityUnleashEvent event = new EntityUnleashEvent(entity.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE, true); -+ if (!event.callEvent()) return; -+ dropLeash = event.isDropLeash(); - } - // CraftBukkit end -- this.dropLeash(); -+ if (dropLeash) { -+ this.dropLeash(); -+ } else { -+ this.removeLeash(); -+ } -+ // Paper end - Expand EntityUnleashEvent - } - - default void closeRangeLeashBehaviour(Entity entity) {} -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index b3c27cdf7d336404403fe09553080835f2d3de49..7d3e165bae2c00737019689b7bf1e74ad2517270 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -1612,8 +1612,15 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab - boolean flag1 = super.startRiding(entity, force); - - if (flag1 && this.isLeashed()) { -- this.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN)); // CraftBukkit -- this.dropLeash(); -+ // Paper start - Expand EntityUnleashEvent -+ EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.UNKNOWN, true); -+ if (!event.callEvent()) { return flag1; } -+ if (event.isDropLeash()) { -+ this.dropLeash(); -+ } else { -+ this.removeLeash(); -+ } -+ // Paper end - Expand EntityUnleashEvent - } - - return flag1; -diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -index 9c6e2124da7c2358d2d524c52d3e77422f15f6e5..45a340fddcec48dfb796f4515a500452adb30c59 100644 ---- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -@@ -102,7 +102,15 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { - public boolean handleLeashAtDistance(Entity leashHolder, float distance) { - if (this.isInSittingPose()) { - if (distance > (float) this.level().paperConfig().misc.maxLeashDistance.or(Leashable.LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance -- this.dropLeash(); -+ // Paper start - Expand EntityUnleashEvent -+ org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(this.getBukkitEntity(), org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.DISTANCE, true); -+ if (!event.callEvent()) return false; -+ if (event.isDropLeash()) { -+ this.dropLeash(); -+ } else { -+ this.removeLeash(); -+ } -+ // Paper end - Expand EntityUnleashEvent - } - - return false; -diff --git a/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java b/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java -index d4955d4174e5c2920d5cccaa4494db2c27284660..d06ec03ad16630f2dfd81cf9f32542bd1c2592de 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java -@@ -119,13 +119,18 @@ public class LeashFenceKnotEntity extends BlockAttachedEntity { - - if (leashable1.isLeashed() && leashable1.getLeashHolder() == this) { - // CraftBukkit start -+ boolean dropLeash = !player.hasInfiniteMaterials(); - if (leashable1 instanceof Entity leashed) { -- if (CraftEventFactory.callPlayerUnleashEntityEvent(leashed, player, hand).isCancelled()) { -+ // Paper start - Expand EntityUnleashEvent -+ org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(leashed, player, hand, dropLeash); -+ dropLeash = event.isDropLeash(); -+ if (event.isCancelled()) { -+ // Paper end - Expand EntityUnleashEvent - die = false; - continue; - } - } -- if (player.getAbilities().instabuild){ -+ if (!dropLeash) { // Paper - Expand EntityUnleashEvent - leashable1.removeLeash(); - } else { - leashable1.dropLeash(); -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 6d1d3451054af05e2381d70d71b99869f37c0901..697c69b60aa45b6a229f3bec77dc728e50a895ce 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1596,8 +1596,10 @@ public class CraftEventFactory { - Bukkit.getPluginManager().callEvent(new PlayerRecipeBookSettingsChangeEvent(player.getBukkitEntity(), bukkitType, open, filter)); - } - -- public static PlayerUnleashEntityEvent callPlayerUnleashEntityEvent(Entity entity, net.minecraft.world.entity.player.Player player, InteractionHand enumhand) { -- PlayerUnleashEntityEvent event = new PlayerUnleashEntityEvent(entity.getBukkitEntity(), (Player) player.getBukkitEntity(), CraftEquipmentSlot.getHand(enumhand)); -+ // Paper start - Expand EntityUnleashEvent -+ public static PlayerUnleashEntityEvent callPlayerUnleashEntityEvent(Entity entity, net.minecraft.world.entity.player.Player player, InteractionHand enumhand, boolean dropLeash) { -+ PlayerUnleashEntityEvent event = new PlayerUnleashEntityEvent(entity.getBukkitEntity(), (Player) player.getBukkitEntity(), CraftEquipmentSlot.getHand(enumhand), dropLeash); -+ // Paper end - Expand EntityUnleashEvent - entity.level().getCraftServer().getPluginManager().callEvent(event); - return event; - } diff --git a/patches/server/0474-Reset-shield-blocking-on-dimension-change.patch b/patches/server/0474-Reset-shield-blocking-on-dimension-change.patch new file mode 100644 index 0000000000..a884682d0d --- /dev/null +++ b/patches/server/0474-Reset-shield-blocking-on-dimension-change.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yive +Date: Sun, 24 Jan 2021 08:55:19 -0800 +Subject: [PATCH] Reset shield blocking on dimension change + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 1dfc696ff2e122c6c61fdd1c7c5761ae81fa75ec..82921c10beee7c37994881618c508fc3a14834eb 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1604,6 +1604,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + PlayerChangedWorldEvent changeEvent = new PlayerChangedWorldEvent(this.getBukkitEntity(), worldserver1.getWorld()); + this.level().getCraftServer().getPluginManager().callEvent(changeEvent); + // CraftBukkit end ++ // Paper start - Reset shield blocking on dimension change ++ if (this.isBlocking()) { ++ this.stopUsingItem(); ++ } ++ // Paper end - Reset shield blocking on dimension change + return this; + } + } diff --git a/patches/server/0475-Add-DragonEggFormEvent.patch b/patches/server/0475-Add-DragonEggFormEvent.patch new file mode 100644 index 0000000000..34506b3c79 --- /dev/null +++ b/patches/server/0475-Add-DragonEggFormEvent.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Trigary +Date: Mon, 25 Jan 2021 14:53:57 +0100 +Subject: [PATCH] Add DragonEggFormEvent + + +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 0e1eceb2b83aaafccbb5d58cf5098cfbc6f25a54..3d1a49d865e17a61ff74c6fe0efbd908447ee730 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 +@@ -410,8 +410,22 @@ public class EndDragonFight { + this.dragonEvent.setVisible(false); + this.spawnExitPortal(true); + this.spawnNewGateway(); ++ // Paper start - Add DragonEggFormEvent ++ BlockPos eggPosition = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)); ++ org.bukkit.craftbukkit.block.CraftBlockState eggState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(this.level, eggPosition); ++ eggState.setData(Blocks.DRAGON_EGG.defaultBlockState()); ++ io.papermc.paper.event.block.DragonEggFormEvent eggEvent = new io.papermc.paper.event.block.DragonEggFormEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this.level, eggPosition), eggState, ++ new org.bukkit.craftbukkit.boss.CraftDragonBattle(this)); ++ // Paper end - Add DragonEggFormEvent + if (this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - Add toggle for always placing the dragon egg +- this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState()); ++ // Paper start - Add DragonEggFormEvent ++ // this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState()); ++ } else { ++ eggEvent.setCancelled(true); ++ } ++ if (eggEvent.callEvent()) { ++ eggEvent.getNewState().update(true); ++ // Paper end - Add DragonEggFormEvent + } + + this.previouslyKilled = true; diff --git a/patches/server/0475-Reset-shield-blocking-on-dimension-change.patch b/patches/server/0475-Reset-shield-blocking-on-dimension-change.patch deleted file mode 100644 index 3126d1c539..0000000000 --- a/patches/server/0475-Reset-shield-blocking-on-dimension-change.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Yive -Date: Sun, 24 Jan 2021 08:55:19 -0800 -Subject: [PATCH] Reset shield blocking on dimension change - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 6344947f445e1da19d21de67a51b88de65eceb7a..f046b8e6307079878d94eab615a5463a807e6c6c 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1604,6 +1604,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - PlayerChangedWorldEvent changeEvent = new PlayerChangedWorldEvent(this.getBukkitEntity(), worldserver1.getWorld()); - this.level().getCraftServer().getPluginManager().callEvent(changeEvent); - // CraftBukkit end -+ // Paper start - Reset shield blocking on dimension change -+ if (this.isBlocking()) { -+ this.stopUsingItem(); -+ } -+ // Paper end - Reset shield blocking on dimension change - return this; - } - } diff --git a/patches/server/0476-Add-DragonEggFormEvent.patch b/patches/server/0476-Add-DragonEggFormEvent.patch deleted file mode 100644 index 34506b3c79..0000000000 --- a/patches/server/0476-Add-DragonEggFormEvent.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trigary -Date: Mon, 25 Jan 2021 14:53:57 +0100 -Subject: [PATCH] Add DragonEggFormEvent - - -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 0e1eceb2b83aaafccbb5d58cf5098cfbc6f25a54..3d1a49d865e17a61ff74c6fe0efbd908447ee730 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 -@@ -410,8 +410,22 @@ public class EndDragonFight { - this.dragonEvent.setVisible(false); - this.spawnExitPortal(true); - this.spawnNewGateway(); -+ // Paper start - Add DragonEggFormEvent -+ BlockPos eggPosition = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)); -+ org.bukkit.craftbukkit.block.CraftBlockState eggState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(this.level, eggPosition); -+ eggState.setData(Blocks.DRAGON_EGG.defaultBlockState()); -+ io.papermc.paper.event.block.DragonEggFormEvent eggEvent = new io.papermc.paper.event.block.DragonEggFormEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this.level, eggPosition), eggState, -+ new org.bukkit.craftbukkit.boss.CraftDragonBattle(this)); -+ // Paper end - Add DragonEggFormEvent - if (this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - Add toggle for always placing the dragon egg -- this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState()); -+ // Paper start - Add DragonEggFormEvent -+ // this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState()); -+ } else { -+ eggEvent.setCancelled(true); -+ } -+ if (eggEvent.callEvent()) { -+ eggEvent.getNewState().update(true); -+ // Paper end - Add DragonEggFormEvent - } - - this.previouslyKilled = true; diff --git a/patches/server/0476-Add-EntityMoveEvent.patch b/patches/server/0476-Add-EntityMoveEvent.patch new file mode 100644 index 0000000000..26e8fba2fe --- /dev/null +++ b/patches/server/0476-Add-EntityMoveEvent.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 11 Feb 2020 21:56:48 -0600 +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 d6fe710a4e3784ba38776a0496eac7fa702aed88..b28a2756429270414f8ef89539f91ce0595d13c6 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1647,6 +1647,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent ++ worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent + + 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 412c1af3282d5d5bbcb7276c6cf90e9ce87668ba..59a94b2decc48b4e277ebb1d3042cc851fa34882 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 + public final LevelStorageSource.LevelStorageAccess convertable; + public final UUID uuid; + public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent ++ public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent + + 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 f025d36c8ae8606172e8166721f09c851784c3cc..728004ca0c0e0ce40f2357ed8dc5f2a86b9cc50a 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3638,6 +3638,20 @@ public abstract class LivingEntity extends Entity implements Attackable { + + this.pushEntities(); + gameprofilerfiller.pop(); ++ // Paper start - Add EntityMoveEvent ++ if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) { ++ if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { ++ Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO); ++ Location to = new Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); ++ io.papermc.paper.event.entity.EntityMoveEvent event = new io.papermc.paper.event.entity.EntityMoveEvent(this.getBukkitLivingEntity(), from, to.clone()); ++ if (!event.callEvent()) { ++ this.absMoveTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch()); ++ } else if (!to.equals(event.getTo())) { ++ this.absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch()); ++ } ++ } ++ } ++ // Paper end - Add EntityMoveEvent + world = this.level(); + if (world instanceof ServerLevel worldserver) { + if (this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { diff --git a/patches/server/0477-Add-EntityMoveEvent.patch b/patches/server/0477-Add-EntityMoveEvent.patch deleted file mode 100644 index c0285a9e47..0000000000 --- a/patches/server/0477-Add-EntityMoveEvent.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 11 Feb 2020 21:56:48 -0600 -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 d6fe710a4e3784ba38776a0496eac7fa702aed88..b28a2756429270414f8ef89539f91ce0595d13c6 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1647,6 +1647,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent -+ worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent - - 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 e56f9e823f9460854c6f0f2f05422136c12aabba..de948bb8903c48e0431c1a46f5aac4fc1828b581 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 - public final LevelStorageSource.LevelStorageAccess convertable; - public final UUID uuid; - public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent -+ public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent - - 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 f025d36c8ae8606172e8166721f09c851784c3cc..728004ca0c0e0ce40f2357ed8dc5f2a86b9cc50a 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3638,6 +3638,20 @@ public abstract class LivingEntity extends Entity implements Attackable { - - this.pushEntities(); - gameprofilerfiller.pop(); -+ // Paper start - Add EntityMoveEvent -+ if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) { -+ if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { -+ Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO); -+ Location to = new Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); -+ io.papermc.paper.event.entity.EntityMoveEvent event = new io.papermc.paper.event.entity.EntityMoveEvent(this.getBukkitLivingEntity(), from, to.clone()); -+ if (!event.callEvent()) { -+ this.absMoveTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch()); -+ } else if (!to.equals(event.getTo())) { -+ this.absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch()); -+ } -+ } -+ } -+ // Paper end - Add EntityMoveEvent - world = this.level(); - if (world instanceof ServerLevel worldserver) { - if (this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { diff --git a/patches/server/0477-added-option-to-disable-pathfinding-updates-on-block.patch b/patches/server/0477-added-option-to-disable-pathfinding-updates-on-block.patch new file mode 100644 index 0000000000..240905a8fd --- /dev/null +++ b/patches/server/0477-added-option-to-disable-pathfinding-updates-on-block.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: lukas81298 +Date: Mon, 25 Jan 2021 14:37:57 +0100 +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 59a94b2decc48b4e277ebb1d3042cc851fa34882..4f2d1a70007cd0a30567886e970bbfda6d750488 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1363,6 +1363,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + + this.getChunkSource().blockChanged(pos); + this.pathTypesByPosCache.invalidate(pos); ++ if (this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates + VoxelShape voxelshape = oldState.getCollisionShape(this, pos); + VoxelShape voxelshape1 = newState.getCollisionShape(this, pos); + +@@ -1404,6 +1405,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } + + } ++ } // Paper - option to disable pathfinding updates + } + + @Override diff --git a/patches/server/0478-Inline-shift-direction-fields.patch b/patches/server/0478-Inline-shift-direction-fields.patch new file mode 100644 index 0000000000..e47ea8a571 --- /dev/null +++ b/patches/server/0478-Inline-shift-direction-fields.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Steinborn +Date: Mon, 18 Jan 2021 20:45:25 -0500 +Subject: [PATCH] Inline shift direction fields + +Removes a layer of indirection for EnumDirection.getAdjacent(X|Y|Z)(), which is in the +critical section for much of the server, including the lighting engine. + +diff --git a/src/main/java/net/minecraft/core/Direction.java b/src/main/java/net/minecraft/core/Direction.java +index acecb0e9df1b157579d2b438abf1568d7672b570..690e1d2394e68356c56a39ac083cc53ee0388d71 100644 +--- a/src/main/java/net/minecraft/core/Direction.java ++++ b/src/main/java/net/minecraft/core/Direction.java +@@ -57,6 +57,12 @@ public enum Direction implements StringRepresentable { + .sorted(Comparator.comparingInt(direction -> direction.data2d)) + .toArray(Direction[]::new); + ++ // Paper start - Perf: Inline shift direction fields ++ private final int adjX; ++ private final int adjY; ++ private final int adjZ; ++ // Paper end - Perf: Inline shift direction fields ++ + private Direction( + final int id, + final int idOpposite, +@@ -74,6 +80,11 @@ public enum Direction implements StringRepresentable { + this.axisDirection = direction; + this.normal = vector; + this.normalVec3 = Vec3.atLowerCornerOf(vector); ++ // Paper start - Perf: Inline shift direction fields ++ this.adjX = vector.getX(); ++ this.adjY = vector.getY(); ++ this.adjZ = vector.getZ(); ++ // Paper end - Perf: Inline shift direction fields + } + + public static Direction[] orderedByNearest(Entity entity) { +@@ -247,15 +258,15 @@ public enum Direction implements StringRepresentable { + } + + public int getStepX() { +- return this.normal.getX(); ++ return this.adjX; // Paper - Perf: Inline shift direction fields + } + + public int getStepY() { +- return this.normal.getY(); ++ return this.adjY; // Paper - Perf: Inline shift direction fields + } + + public int getStepZ() { +- return this.normal.getZ(); ++ return this.adjZ; // Paper - Perf: Inline shift direction fields + } + + public Vector3f step() { diff --git a/patches/server/0478-added-option-to-disable-pathfinding-updates-on-block.patch b/patches/server/0478-added-option-to-disable-pathfinding-updates-on-block.patch deleted file mode 100644 index dd3704bba6..0000000000 --- a/patches/server/0478-added-option-to-disable-pathfinding-updates-on-block.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: lukas81298 -Date: Mon, 25 Jan 2021 14:37:57 +0100 -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 de948bb8903c48e0431c1a46f5aac4fc1828b581..dc2b8d8e62cf1405191aa4fc8d4fa548c7249032 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1363,6 +1363,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - - this.getChunkSource().blockChanged(pos); - this.pathTypesByPosCache.invalidate(pos); -+ if (this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates - VoxelShape voxelshape = oldState.getCollisionShape(this, pos); - VoxelShape voxelshape1 = newState.getCollisionShape(this, pos); - -@@ -1404,6 +1405,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - - } -+ } // Paper - option to disable pathfinding updates - } - - @Override diff --git a/patches/server/0479-Allow-adding-items-to-BlockDropItemEvent.patch b/patches/server/0479-Allow-adding-items-to-BlockDropItemEvent.patch new file mode 100644 index 0000000000..7b84a8ac96 --- /dev/null +++ b/patches/server/0479-Allow-adding-items-to-BlockDropItemEvent.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Wed, 20 Jan 2021 14:23:37 -0600 +Subject: [PATCH] Allow adding items to BlockDropItemEvent + + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 697c69b60aa45b6a229f3bec77dc728e50a895ce..49efae40345fcfca8f80fcc541dcfde1b8a8b07b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -461,13 +461,30 @@ public class CraftEventFactory { + } + + public static void handleBlockDropItemEvent(Block block, BlockState state, ServerPlayer player, List items) { +- BlockDropItemEvent event = new BlockDropItemEvent(block, state, player.getBukkitEntity(), Lists.transform(items, (item) -> (org.bukkit.entity.Item) item.getBukkitEntity())); ++ // Paper start - Allow adding items to BlockDropItemEvent ++ List list = new ArrayList<>(); ++ for (ItemEntity item : items) { ++ list.add((Item) item.getBukkitEntity()); ++ } ++ BlockDropItemEvent event = new BlockDropItemEvent(block, state, player.getBukkitEntity(), list); ++ // Paper end - Allow adding items to BlockDropItemEvent + Bukkit.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { +- for (ItemEntity item : items) { +- item.level().addFreshEntity(item); ++ // Paper start - Allow adding items to BlockDropItemEvent ++ for (Item bukkit : list) { ++ if (!bukkit.isValid()) { ++ Entity item = ((org.bukkit.craftbukkit.entity.CraftItem) bukkit).getHandle(); ++ item.level().addFreshEntity(item); ++ } ++ } ++ } else { ++ for (Item bukkit : list) { ++ if (bukkit.isValid()) { ++ bukkit.remove(); ++ } + } ++ // Paper end - Allow adding items to BlockDropItemEvent + } + } + diff --git a/patches/server/0479-Inline-shift-direction-fields.patch b/patches/server/0479-Inline-shift-direction-fields.patch deleted file mode 100644 index e47ea8a571..0000000000 --- a/patches/server/0479-Inline-shift-direction-fields.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrew Steinborn -Date: Mon, 18 Jan 2021 20:45:25 -0500 -Subject: [PATCH] Inline shift direction fields - -Removes a layer of indirection for EnumDirection.getAdjacent(X|Y|Z)(), which is in the -critical section for much of the server, including the lighting engine. - -diff --git a/src/main/java/net/minecraft/core/Direction.java b/src/main/java/net/minecraft/core/Direction.java -index acecb0e9df1b157579d2b438abf1568d7672b570..690e1d2394e68356c56a39ac083cc53ee0388d71 100644 ---- a/src/main/java/net/minecraft/core/Direction.java -+++ b/src/main/java/net/minecraft/core/Direction.java -@@ -57,6 +57,12 @@ public enum Direction implements StringRepresentable { - .sorted(Comparator.comparingInt(direction -> direction.data2d)) - .toArray(Direction[]::new); - -+ // Paper start - Perf: Inline shift direction fields -+ private final int adjX; -+ private final int adjY; -+ private final int adjZ; -+ // Paper end - Perf: Inline shift direction fields -+ - private Direction( - final int id, - final int idOpposite, -@@ -74,6 +80,11 @@ public enum Direction implements StringRepresentable { - this.axisDirection = direction; - this.normal = vector; - this.normalVec3 = Vec3.atLowerCornerOf(vector); -+ // Paper start - Perf: Inline shift direction fields -+ this.adjX = vector.getX(); -+ this.adjY = vector.getY(); -+ this.adjZ = vector.getZ(); -+ // Paper end - Perf: Inline shift direction fields - } - - public static Direction[] orderedByNearest(Entity entity) { -@@ -247,15 +258,15 @@ public enum Direction implements StringRepresentable { - } - - public int getStepX() { -- return this.normal.getX(); -+ return this.adjX; // Paper - Perf: Inline shift direction fields - } - - public int getStepY() { -- return this.normal.getY(); -+ return this.adjY; // Paper - Perf: Inline shift direction fields - } - - public int getStepZ() { -- return this.normal.getZ(); -+ return this.adjZ; // Paper - Perf: Inline shift direction fields - } - - public Vector3f step() { diff --git a/patches/server/0480-Add-getMainThreadExecutor-to-BukkitScheduler.patch b/patches/server/0480-Add-getMainThreadExecutor-to-BukkitScheduler.patch new file mode 100644 index 0000000000..2f143cc0b4 --- /dev/null +++ b/patches/server/0480-Add-getMainThreadExecutor-to-BukkitScheduler.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aleksander Jagiello +Date: Sun, 24 Jan 2021 22:17:54 +0100 +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 20760e08b3d9aba86969b886b46deec5b125bf1f..1354ccfbf525e5e64483ac5f443cc2325ba63850 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +@@ -633,4 +633,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)"); + } ++ ++ // Paper start - add getMainThreadExecutor ++ @Override ++ public Executor getMainThreadExecutor(Plugin plugin) { ++ Preconditions.checkArgument(plugin != null, "Plugin cannot be null"); ++ return command -> { ++ Preconditions.checkArgument(command != null, "Command cannot be null"); ++ this.runTask(plugin, command); ++ }; ++ } ++ // Paper end + } diff --git a/patches/server/0480-Allow-adding-items-to-BlockDropItemEvent.patch b/patches/server/0480-Allow-adding-items-to-BlockDropItemEvent.patch deleted file mode 100644 index 7b84a8ac96..0000000000 --- a/patches/server/0480-Allow-adding-items-to-BlockDropItemEvent.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Wed, 20 Jan 2021 14:23:37 -0600 -Subject: [PATCH] Allow adding items to BlockDropItemEvent - - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 697c69b60aa45b6a229f3bec77dc728e50a895ce..49efae40345fcfca8f80fcc541dcfde1b8a8b07b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -461,13 +461,30 @@ public class CraftEventFactory { - } - - public static void handleBlockDropItemEvent(Block block, BlockState state, ServerPlayer player, List items) { -- BlockDropItemEvent event = new BlockDropItemEvent(block, state, player.getBukkitEntity(), Lists.transform(items, (item) -> (org.bukkit.entity.Item) item.getBukkitEntity())); -+ // Paper start - Allow adding items to BlockDropItemEvent -+ List list = new ArrayList<>(); -+ for (ItemEntity item : items) { -+ list.add((Item) item.getBukkitEntity()); -+ } -+ BlockDropItemEvent event = new BlockDropItemEvent(block, state, player.getBukkitEntity(), list); -+ // Paper end - Allow adding items to BlockDropItemEvent - Bukkit.getPluginManager().callEvent(event); - - if (!event.isCancelled()) { -- for (ItemEntity item : items) { -- item.level().addFreshEntity(item); -+ // Paper start - Allow adding items to BlockDropItemEvent -+ for (Item bukkit : list) { -+ if (!bukkit.isValid()) { -+ Entity item = ((org.bukkit.craftbukkit.entity.CraftItem) bukkit).getHandle(); -+ item.level().addFreshEntity(item); -+ } -+ } -+ } else { -+ for (Item bukkit : list) { -+ if (bukkit.isValid()) { -+ bukkit.remove(); -+ } - } -+ // Paper end - Allow adding items to BlockDropItemEvent - } - } - diff --git a/patches/server/0481-Add-getMainThreadExecutor-to-BukkitScheduler.patch b/patches/server/0481-Add-getMainThreadExecutor-to-BukkitScheduler.patch deleted file mode 100644 index 2f143cc0b4..0000000000 --- a/patches/server/0481-Add-getMainThreadExecutor-to-BukkitScheduler.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aleksander Jagiello -Date: Sun, 24 Jan 2021 22:17:54 +0100 -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 20760e08b3d9aba86969b886b46deec5b125bf1f..1354ccfbf525e5e64483ac5f443cc2325ba63850 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -633,4 +633,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)"); - } -+ -+ // Paper start - add getMainThreadExecutor -+ @Override -+ public Executor getMainThreadExecutor(Plugin plugin) { -+ Preconditions.checkArgument(plugin != null, "Plugin cannot be null"); -+ return command -> { -+ Preconditions.checkArgument(command != null, "Command cannot be null"); -+ this.runTask(plugin, command); -+ }; -+ } -+ // Paper end - } diff --git a/patches/server/0481-living-entity-allow-attribute-registration.patch b/patches/server/0481-living-entity-allow-attribute-registration.patch new file mode 100644 index 0000000000..ef6df5b4ed --- /dev/null +++ b/patches/server/0481-living-entity-allow-attribute-registration.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: ysl3000 +Date: Sat, 24 Oct 2020 16:37:44 +0200 +Subject: [PATCH] living entity allow attribute registration + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java +index b3707ca404245ae048ddba4ce2190c0801b474d4..fb967ac7b3e7828301f08a7fe9b039441cf7da30 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java ++++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java +@@ -162,4 +162,12 @@ public class AttributeMap { + } + } + } ++ ++ // Paper - start - living entity allow attribute registration ++ public void registerAttribute(Holder attributeBase) { ++ AttributeInstance attributeModifiable = new AttributeInstance(attributeBase, AttributeInstance::getAttribute); ++ attributes.put(attributeBase, attributeModifiable); ++ } ++ // Paper - end - living entity allow attribute registration ++ + } +diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java +index 5678d2007d5adf45dec0638c5dd848b601801814..0a7ed5a4f1644a70d8f98ad7a6962b814ad6daf4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java +@@ -35,4 +35,11 @@ public class CraftAttributeMap implements Attributable { + + return (nms == null) ? null : new CraftAttributeInstance(nms, attribute); + } ++ // Paper start - living entity allow attribute registration ++ @Override ++ public void registerAttribute(Attribute attribute) { ++ Preconditions.checkArgument(attribute != null, "attribute"); ++ handle.registerAttribute(CraftAttribute.bukkitToMinecraftHolder(attribute)); ++ } ++ // Paper end - living entity allow attribute registration + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 1ca252f36500322d56c0c12b6ec80c069214c0e8..a4be1eea356ba99358d707381df70032ded42140 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -775,6 +775,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + return this.getHandle().craftAttributes.getAttribute(attribute); + } + ++ // Paper start - living entity allow attribute registration ++ @Override ++ public void registerAttribute(Attribute attribute) { ++ getHandle().craftAttributes.registerAttribute(attribute); ++ } ++ // Paper end - living entity allow attribute registration ++ + @Override + public void setAI(boolean ai) { + if (this.getHandle() instanceof Mob) { diff --git a/patches/server/0482-fix-dead-slime-setSize-invincibility.patch b/patches/server/0482-fix-dead-slime-setSize-invincibility.patch new file mode 100644 index 0000000000..494e56127e --- /dev/null +++ b/patches/server/0482-fix-dead-slime-setSize-invincibility.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Trigary +Date: Fri, 5 Feb 2021 22:12:13 +0100 +Subject: [PATCH] fix dead slime setSize invincibility + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java +index 3d9b7c0e128ea05bec5600c774e9685998b71cac..e48f7d1cbec4a2319745ba48a5d44ab9925214e2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java +@@ -16,7 +16,7 @@ public class CraftSlime extends CraftMob implements Slime, CraftEnemy { + + @Override + public void setSize(int size) { +- this.getHandle().setSize(size, true); ++ this.getHandle().setSize(size, /* true */ getHandle().isAlive()); // Paper - fix dead slime setSize invincibility + } + + @Override diff --git a/patches/server/0482-living-entity-allow-attribute-registration.patch b/patches/server/0482-living-entity-allow-attribute-registration.patch deleted file mode 100644 index ef6df5b4ed..0000000000 --- a/patches/server/0482-living-entity-allow-attribute-registration.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: ysl3000 -Date: Sat, 24 Oct 2020 16:37:44 +0200 -Subject: [PATCH] living entity allow attribute registration - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -index b3707ca404245ae048ddba4ce2190c0801b474d4..fb967ac7b3e7828301f08a7fe9b039441cf7da30 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -@@ -162,4 +162,12 @@ public class AttributeMap { - } - } - } -+ -+ // Paper - start - living entity allow attribute registration -+ public void registerAttribute(Holder attributeBase) { -+ AttributeInstance attributeModifiable = new AttributeInstance(attributeBase, AttributeInstance::getAttribute); -+ attributes.put(attributeBase, attributeModifiable); -+ } -+ // Paper - end - living entity allow attribute registration -+ - } -diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java -index 5678d2007d5adf45dec0638c5dd848b601801814..0a7ed5a4f1644a70d8f98ad7a6962b814ad6daf4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java -@@ -35,4 +35,11 @@ public class CraftAttributeMap implements Attributable { - - return (nms == null) ? null : new CraftAttributeInstance(nms, attribute); - } -+ // Paper start - living entity allow attribute registration -+ @Override -+ public void registerAttribute(Attribute attribute) { -+ Preconditions.checkArgument(attribute != null, "attribute"); -+ handle.registerAttribute(CraftAttribute.bukkitToMinecraftHolder(attribute)); -+ } -+ // Paper end - living entity allow attribute registration - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 1ca252f36500322d56c0c12b6ec80c069214c0e8..a4be1eea356ba99358d707381df70032ded42140 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -775,6 +775,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - return this.getHandle().craftAttributes.getAttribute(attribute); - } - -+ // Paper start - living entity allow attribute registration -+ @Override -+ public void registerAttribute(Attribute attribute) { -+ getHandle().craftAttributes.registerAttribute(attribute); -+ } -+ // Paper end - living entity allow attribute registration -+ - @Override - public void setAI(boolean ai) { - if (this.getHandle() instanceof Mob) { diff --git a/patches/server/0483-Merchant-getRecipes-should-return-an-immutable-list.patch b/patches/server/0483-Merchant-getRecipes-should-return-an-immutable-list.patch new file mode 100644 index 0000000000..d40a7cf8d7 --- /dev/null +++ b/patches/server/0483-Merchant-getRecipes-should-return-an-immutable-list.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Wed, 10 Feb 2021 14:53:36 -0800 +Subject: [PATCH] Merchant#getRecipes should return an immutable list + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java +index 770686757a87d923ecb0361ba0939b4f7d184d76..72b5f6724278ec78605d7f435ef7ca340f195f5b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java +@@ -16,7 +16,7 @@ public interface CraftMerchant extends Merchant { + + @Override + default List getRecipes() { +- return Collections.unmodifiableList(Lists.transform(this.getMerchant().getOffers(), new Function() { ++ return List.copyOf(Lists.transform(this.getMerchant().getOffers(), new Function() { // Paper - javadoc says 'an immutable list of trades' - not 'an unmodifiable view of a list of trades'. fixes issue with setRecipes(getRecipes()) + @Override + public MerchantRecipe apply(net.minecraft.world.item.trading.MerchantOffer recipe) { + return recipe.asBukkit(); diff --git a/patches/server/0483-fix-dead-slime-setSize-invincibility.patch b/patches/server/0483-fix-dead-slime-setSize-invincibility.patch deleted file mode 100644 index 494e56127e..0000000000 --- a/patches/server/0483-fix-dead-slime-setSize-invincibility.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trigary -Date: Fri, 5 Feb 2021 22:12:13 +0100 -Subject: [PATCH] fix dead slime setSize invincibility - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java -index 3d9b7c0e128ea05bec5600c774e9685998b71cac..e48f7d1cbec4a2319745ba48a5d44ab9925214e2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSlime.java -@@ -16,7 +16,7 @@ public class CraftSlime extends CraftMob implements Slime, CraftEnemy { - - @Override - public void setSize(int size) { -- this.getHandle().setSize(size, true); -+ this.getHandle().setSize(size, /* true */ getHandle().isAlive()); // Paper - fix dead slime setSize invincibility - } - - @Override diff --git a/patches/server/0484-Expose-Tracked-Players.patch b/patches/server/0484-Expose-Tracked-Players.patch new file mode 100644 index 0000000000..5e7f3c585c --- /dev/null +++ b/patches/server/0484-Expose-Tracked-Players.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tom +Date: Fri, 26 Feb 2021 16:24:25 -0600 +Subject: [PATCH] Expose Tracked Players + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index dbb1a52b1e5871bbb1ccbd300b8edb9aa0f56e49..78afac72265e3f586c0203951b8237832fb7c6fb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1065,4 +1065,21 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return getHandle().isTicking(); + } + // Paper end - isTicking API ++ ++ // Paper start - tracked players API ++ @Override ++ public Set getTrackedPlayers() { ++ ServerLevel world = (net.minecraft.server.level.ServerLevel)this.entity.level(); ++ ChunkMap.TrackedEntity tracker = world == null ? null : world.getChunkSource().chunkMap.entityMap.get(this.entity.getId()); ++ if (tracker == null) { ++ return java.util.Collections.emptySet(); ++ } ++ ++ Set set = new java.util.HashSet<>(tracker.seenBy.size()); ++ for (net.minecraft.server.network.ServerPlayerConnection connection : tracker.seenBy) { ++ set.add(connection.getPlayer().getBukkitEntity().getPlayer()); ++ } ++ return set; ++ } ++ // Paper end - tracked players API + } diff --git a/patches/server/0484-Merchant-getRecipes-should-return-an-immutable-list.patch b/patches/server/0484-Merchant-getRecipes-should-return-an-immutable-list.patch deleted file mode 100644 index d40a7cf8d7..0000000000 --- a/patches/server/0484-Merchant-getRecipes-should-return-an-immutable-list.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Wed, 10 Feb 2021 14:53:36 -0800 -Subject: [PATCH] Merchant#getRecipes should return an immutable list - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java -index 770686757a87d923ecb0361ba0939b4f7d184d76..72b5f6724278ec78605d7f435ef7ca340f195f5b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java -@@ -16,7 +16,7 @@ public interface CraftMerchant extends Merchant { - - @Override - default List getRecipes() { -- return Collections.unmodifiableList(Lists.transform(this.getMerchant().getOffers(), new Function() { -+ return List.copyOf(Lists.transform(this.getMerchant().getOffers(), new Function() { // Paper - javadoc says 'an immutable list of trades' - not 'an unmodifiable view of a list of trades'. fixes issue with setRecipes(getRecipes()) - @Override - public MerchantRecipe apply(net.minecraft.world.item.trading.MerchantOffer recipe) { - return recipe.asBukkit(); diff --git a/patches/server/0485-Expose-Tracked-Players.patch b/patches/server/0485-Expose-Tracked-Players.patch deleted file mode 100644 index 5e7f3c585c..0000000000 --- a/patches/server/0485-Expose-Tracked-Players.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Tom -Date: Fri, 26 Feb 2021 16:24:25 -0600 -Subject: [PATCH] Expose Tracked Players - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index dbb1a52b1e5871bbb1ccbd300b8edb9aa0f56e49..78afac72265e3f586c0203951b8237832fb7c6fb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1065,4 +1065,21 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return getHandle().isTicking(); - } - // Paper end - isTicking API -+ -+ // Paper start - tracked players API -+ @Override -+ public Set getTrackedPlayers() { -+ ServerLevel world = (net.minecraft.server.level.ServerLevel)this.entity.level(); -+ ChunkMap.TrackedEntity tracker = world == null ? null : world.getChunkSource().chunkMap.entityMap.get(this.entity.getId()); -+ if (tracker == null) { -+ return java.util.Collections.emptySet(); -+ } -+ -+ Set set = new java.util.HashSet<>(tracker.seenBy.size()); -+ for (net.minecraft.server.network.ServerPlayerConnection connection : tracker.seenBy) { -+ set.add(connection.getPlayer().getBukkitEntity().getPlayer()); -+ } -+ return set; -+ } -+ // Paper end - tracked players API - } diff --git a/patches/server/0485-Improve-ServerGUI.patch b/patches/server/0485-Improve-ServerGUI.patch new file mode 100644 index 0000000000..8dde1d1a9b --- /dev/null +++ b/patches/server/0485-Improve-ServerGUI.patch @@ -0,0 +1,431 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: AlexProgrammerDE <40795980+AlexProgrammerDE@users.noreply.github.com> +Date: Sat, 3 Oct 2020 08:27:40 +0200 +Subject: [PATCH] Improve ServerGUI + +- Added logo to server frame +- Show tps in the server stats + +diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java +index f93373d28d741e1f8a53e07b4e328ce9c4e1657f..12b327eea95e0de9e9c39b7d039badee8ec46508 100644 +--- a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java ++++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java +@@ -58,9 +58,22 @@ public class RAMDetails extends JList { + public void update() { + GraphData data = RAMGraph.DATA.peekLast(); + Vector vector = new Vector<>(); ++ ++ // Follows CraftServer#getTPS ++ double[] tps = new double[] { ++ server.tps1.getAverage(), ++ server.tps5.getAverage(), ++ server.tps15.getAverage() ++ }; ++ String[] tpsAvg = new String[tps.length]; ++ ++ for ( int g = 0; g < tps.length; g++) { ++ tpsAvg[g] = format( tps[g] ); ++ } + vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)"); + vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb"); + vector.add("Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms"); ++ vector.add("TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg)); + setListData(vector); + } + +@@ -71,4 +84,8 @@ public class RAMDetails extends JList { + } + return ((double) total / (double) tickTimes.length) * 1.0E-6D; + } ++ ++ private static String format(double tps) { ++ return ( ( tps > 21.0 ) ? "*" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 ); ++ } + } +diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java +index 8b570b0c3967a22c085f390110cb29cbd9c8feff..4d3fe4f56e0b264fa030409919caf52d5f421d46 100644 +--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java ++++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java +@@ -59,6 +59,15 @@ public class MinecraftServerGui extends JComponent { + jframe.pack(); + jframe.setLocationRelativeTo((Component) null); + jframe.setVisible(true); ++ jframe.setName("Minecraft server"); // Paper - Improve ServerGUI ++ ++ // Paper start - Improve ServerGUI ++ try { ++ jframe.setIconImage(javax.imageio.ImageIO.read(Objects.requireNonNull(MinecraftServerGui.class.getClassLoader().getResourceAsStream("logo.png")))); ++ } catch (java.io.IOException ignore) { ++ } ++ // Paper end - Improve ServerGUI ++ + jframe.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent windowevent) { + if (!servergui.isClosing.getAndSet(true)) { +diff --git a/src/main/java/net/minecraft/server/gui/StatsComponent.java b/src/main/java/net/minecraft/server/gui/StatsComponent.java +index 6e9c6d556ed55325e36d191fc9d1508c00879671..096c89bd01cec2abd151bf6fffc4847d1bcd548f 100644 +--- a/src/main/java/net/minecraft/server/gui/StatsComponent.java ++++ b/src/main/java/net/minecraft/server/gui/StatsComponent.java +@@ -34,10 +34,19 @@ public class StatsComponent extends JComponent { + + private void tick() { + long l = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); ++ // Paper start - Improve ServerGUI ++ double[] tps = org.bukkit.Bukkit.getTPS(); ++ String[] tpsAvg = new String[tps.length]; ++ ++ for ( int g = 0; g < tps.length; g++) { ++ tpsAvg[g] = format( tps[g] ); ++ } + this.msgs[0] = "Memory use: " + l / 1024L / 1024L + " mb (" + Runtime.getRuntime().freeMemory() * 100L / Runtime.getRuntime().maxMemory() + "% free)"; + this.msgs[1] = "Avg tick: " + + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double)TimeUtil.NANOSECONDS_PER_MILLISECOND) + + " ms"; ++ this.msgs[2] = "TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg); ++ // Paper end - Improve ServerGUI + this.values[this.vp++ & 0xFF] = (int)(l * 100L / Runtime.getRuntime().maxMemory()); + this.repaint(); + } +@@ -66,4 +75,10 @@ public class StatsComponent extends JComponent { + public void close() { + this.timer.stop(); + } ++ ++ // Paper start - Improve ServerGUI ++ private static String format(double tps) { ++ return (( tps > 21.0 ) ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0); // only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise ++ } ++ // Paper end - Improve ServerGUI + } +diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png +new file mode 100644 +index 0000000000000000000000000000000000000000..8b924977b7886df9ab8790b1e4ff9b1c04a2af45 +GIT binary patch +literal 16900 +zcmaicV|1Ng^k&Q(Hn!T>_Kj`Zc4OO48rwD-Gw*(Xv_UIGaL4*?7e3`t5-R2lSh^xqd84Cs4}W^FDQn9zijsF13M{zVR~<`0dB +z;hww3Rk_uLO*yyZ^N(arMN#SjFcHEi60E_fZug`IjtJ^LVtno=lKj+Jze{_WszRIN1X*HUTCH>C_wc;+D)6YYT +z*RWmTUi`Puu_Uwkj6-qwu_Ue*kO&$%=o%J?6*rej_Ock3znkGIb6 +zWm&yS2Z9LS7slFgUx+?ilDgQBdj7`ruw|IVzJ@wV{&tD)G@SPTMW@9Wl5lcsuU~6` +z7raw|%Or|@Pnlh`7!!rA1H$`p;zz}+92Tp2bFmKDAL`nrC>)<{qBHso +zvJ6|o^vMxL?frh4XZ`3WdH7s_NI0p@{EElbnX*!yp;Vtx&K&w$&to`sW +z79>enm;xWhu;ZKKIN}-h!eBKZM6j$9~*Q(SlE*i_bHS0o#tPY +z5-j+ww|x>h9%`RLUixM!e%f0qVAe5GH83X6?!#^_j-M@lO@*-aD%NMF2;Hg^Wgh@}elrPA3o_&(- +zeNyws4es~%;K1o+pfG(Z!G-nFWzl7)ejRNxY?M~uI=I&MYuz@4>GLH*ptjlQJ`LYr +z*KIIVzBhKHIDwe`X2hc@gsdjzXxX%b<_#kc$vIHFi2)-XM1=fs(`g?0)M{lcJXwp< +zBgIdDXM&n-=+_%;1a?sE$oeN{r%w=8tFfAlQopAk +z%wrVN=r>)oZ0w7^M~Xi~qp6lEaABgF(ck7V3Un;@cg|ODuD7@fw~OZ;^TQV +z$&4AiUj}-4;o`6JV$Y4C2G +z8hVweUdzl78hWzD|&J_)oRr2JdJP +zA&lca);^P(q@hQb9-kqNXVo9An7Q3NoAtyRQw-@JUDD$oluryjE +z3{zzbZhStP-K;xw@Yxf-B=4h(p=4f`k8p2DH$>qQLPR!szD!2|vJ}J`C6=EoRwG^+ +z;`ZDv1SGVO+?IqSxpxSM^_V~@2E+~dZQdl+oz;TP1MX+XXwugMy?Z5AoZ7#R33Y@T +zM)w4;9L0szO3>6i#4fV3q49@wu&`zcvQ!d8!m*dpn&7pp0Y=;QbiyOzhC7)Ki7tDt +zXaIqysWqx53ZgHlO)|YRDG**$7&F{0a8VEECY`3;yx)F>2;4Xr&gC;Iqiqx;orWkF +z8xk0Ty-mK&z`^~Fbs#S;;Qd@1ZFJh4R`+H>Wx$xgn>^oka;w9~QfR>rS7lYHG?D#o +z6Jo`Qg_-DP +zX@kdURs~L5?afF*73QF!=HQ?vIysP;FNCMBfA*}*&%$eDHh5L|y~D=C^v8(wdtcYZ +z)8Q|56BuZ~3~KpF-oKg|5Uf@Ac15Z>sP<9hpm(E>^cgr8dMxGhn7mnWA+JPK+EGR; +zCfK+V1&Xi1M6CUFIA+oJqr(aF3W_=ph7h;IVlqq&xJ=d(CqczQwL>f*A$gJW_|iZw +z&>!^cGyI)UH(_%jFMta0ci8K;?^D#C4_`@%@wP6R4qvs8y@ecdj|*ia7Exg3*BpG4 +z%Dqav(-_hWolzv04-3Ygs)Z~U$`R?hQq2Is2`RWS%z4?!GF2CryzMjCEFg_Y%K+yz +zG8tm;0X{;XG5?BBT|pMZ296(fGUtoF_$Ryrso&s;Cc!g3a;pYOn-tjPvW+1)iAQ)I +zaPyG(wl0MZUqz_Z!4+oEh$t>QIaiZ+J1|fQdfugliOCAg+6D!~3<-k#gA8N#Rk3@5 +z&u3Yevetsi3m`sm2Ntt>FV(PfME~wR=LFu+2@Noy&wr###hgP3mjy&H03re#97OQ% +zsZ;NtktNoC?s@G44Num-@G1zw*?jMf)dA`SWJHyI-Lp=m +zyv8V97L8$~?>Sf(&Ee27TQvEf=-_%~EL56_n`*ZRVS`=4Ka4&HGjr9P8e3rf;8BK& +z&0s~H!Z|V-mPt9vUj?5&%Sa@;XK~`TS$ylgW4|1h&I!<9c6_zoDdR2)FLErHw%Sow +zwc_2ZKizcAMchMvZ^6OY8)uiUt&RwA(`3@dzgihQ1MSrNi;ruq-C+?oVa@U0x +z(>^4ei3Bedg+!LX52G(u@W4P&3sdv45%OawU(*aQat~OuEf?Hi6Zi>__qCd)nw0_j +zvUwA_6WQ5tnFsl_AZNz8L8L*=L4?0A>inj9l&C`AC71u=H +z?bu{Q_=al@1+|F&El|te2eQB@?#+g(D(LjFx>w=0X;CJ|CQc@tuin_)Rd$KH$Y9P9 +z${MAq+Ns2`>_SLAfKm9~%?U2bK6>hiDEbdUD#NMd$hR*wFx8TxWVY3Za +zM&tRPhR$htT-*KlZT-SGBy4YD;6aZfAz^Jt1`=ABifztn#D_;u)2WTa-Bo^EKL;=o +zDc6Ov2x3ybU1B6gkFjv-UvyFl^(EFkIb4ht2Z(*io4 +zW(6^Rp7OMxVh73mYH?bkbxgXB=+TL>U^8OY>=P$oXPkGAmF?6#80T +z+e?24uzuJC8?nCu`7)ef&Nu8x+`0%wOB9wmZ^(+|&$!T80~3uj?NRH)aNhf~#vN9e +zem1VW#bKd$SZ4ufS0-pzoJ%P7UWdT@8yg`1+kpYLV153t;UJy~P8@7sO+#{ePIXcSgw}v2XayA<>Jxh}D)tMOGRgJY0QEJs` +z{>aB;ssVeqKi-6L#(PnBpPuOu<4Rf*GWVk8BdMCd} +zc^_!LU3n2YWBEk1?0<%f@MkB;t#h0%&cixNCZn@Lft$eDVl6z=l@Ga}k<7cF5n!!o +zXet^Q3;AyG!j)+$=3U>7D5cEf)=YMZ)jSZ?)!6EoSa3kU!3W2Xn`K`PqR|ML`Ju!A)|K2`l1>ErJG>o*qIC72B&jHYe36od@P! +zi)qQ9Y7g*>N;Y4;sSLlPxvM;q-Tzw2m;Zx=x>{mk0;Ed5zA?Hb1FrDGc6-;m+iSFU +zc22aC&R^-iyw5vE$D?GWWo7A5o@@>d3_uD92sGM_-tlsdQ?ZbAnF4LsSxDj&0TFgO +zFbB*@;0<;Y0es>tB&~M12_up)gRS(Ce{seFR$9$~MC8~S%gCTV+2AIiH`gndEW2~H +z`z|RK5KuxIccy|!;Bkm8puw0EcWFE{ij71G*o4( +z0~y!3%z_nq1kdh3x<;XVQS{_v?Q3|H1so1Z#CL|Zm2Z&7-mTO?&1?U-oogOAE4Cm{ +z`d4o(XCnWH-J^hx&?7X^xHns&B`u2*skUy`s~w=0252bVaZy(}U?e5?u>fG!UbYaS +z4Gz$YBX|~|U$??YUR+zxw2g5F_OJB7viI^}qx|ouEswnc0o{D4T~~|912EVr9)4P& +zS=*@uBmgy>GC)sz_8A$Iga2y-R#LKP$zyVe7P=4Vrn@Q)Fp6mG;Nall=^07<{OPT~ +zPDD~5M}Py>^H&ikOMCrXaXjFMyNuyNg$gXaPOE4z3=$o3Jt(guFuvAQbA?*MR;Dx}r~+zsgJ +zzCtQ*$r?UAKNl$E39K|(pdcV17*;zU{VtG7{)QDicnC&XAit07AxkJs2xbNxkEh-l +ztI=-hZ#0{5e0{huHk5pMKFXUdk-_HT=8j~#**>ze%L-Vq--ELbc7OqlEqqgfDL$7| +z^zia3^m~7il#>&4bK{s6W!C%o9eQ_nw_LRXoq&)qk2e`~Carh!_+@C+^?4E@nB?8v +zrP(B~aF_-3_5wx4#3EgX2f|T2iDX6dBot9e+}zxz-+7y;fop?^#LWumnJ%(ER<|F> +z44(0)x_-m7iZI17bV#w5<;|{V>IZ-R+z|XI2d!L0M$z{_~PzI|b} +z_>I9TkwT-USfkDEyuoB7YJe7^SUeW*JCd>d31w)Viag>w +zE)Hcnu_U(A@CEh^w;UM0IVsDf+yNUB)lCpiM=a>2dMSVx95URpuHBLGh>h8fgM&77%eeba~6*@>lA8=;7iEw2QP4d^IvP +z8fpiWc?lq5kxp*C)nS|HY^i2ov(x?A!{1u(mk%xyJ_nmAsx{Zt=LV=Ta0-O}2|y4O +z5yIAhMw5|xp3lvw|Ps$0W*KZd^Wlj=W@{AaG=^es3_){Y~Jis`IYYiWN~ho|DLil1qRD5 +zN6xAlvXG=U-8`VKVHr!k-;5Bi)EfnJRTtvY$;jR$#e%~lxMV?xboY;JA{IT_^y}D0 +zw1mJ8tVoSO-(}absB6M8b$Zqe)Ok0$OkaA#I +z48@e8TAlv;PmB6dbP|{7<%qt@Ea>I;PRL4)=M`_G!A40Y$Xy1Mum)I0#!3<77H4)u +zI6c{)TUsy&o^*@2H9Bp>QJA#S8$`zN?+@z^IIQL|VxYEQfVw~Oc}Wq!FS`G2T=aDu +z-DMYe(1$x=331oN(i#yV%?Q)lcY`}FpGRp*74@@$fX%pE+dAGOh5QRhJ&mcaXOhk4 +zLi_pirw^Zws;d9n^#IE8T1ypZDX|crNABquU?iL2;Ql%4Vg5cNBt}OJdbLKnEi|`g2q%v70%eM&7 +z5gdFefu8Ix3n54MC +zW40SGT11ajrrm5AI24T?-2$|VMsU%VX}AMmt>Pr~B}#An{>%QG>_1FQYV^)CExzx2 +z&7E_9c!fpiCLci|F3H*eM2DQQRtQp4>V2RP=KX3ZVw#OXuFxj$VDmM&HQD{*dc7301976VQyI69%EFvxxn>qC&Lo-`%ImvM +zCv>AXKPcD26Z_;m`1pw)uF6Mp=RnShU^yM81!?jbl!v#-kSa#RLhSOG0?yp1YB6Jr +zW=GrO|0zIRSHiH?DYiO+$EpdMkwz#4I6V(J12-W0+dAo4J*?nDQrFI<*}a92Y%1bU +z`RC_4tyg7>R(8{ +zA8*g?PWv##WoF+p0bJe>whg#+(1_+A+)9HS$|n?k;(r=Le*vR;57rn)2& +zEkD8KBSZm#3Drt?t!*#s#>0+yUNysIKRg=t`KSOcSHieiUP0z8F_$tZ(ciPnq_o~@ +z%-{zhbs{i7 +zt~8q8%WO|MF(FE_ye*bl_-@NcA!S9$IMb6x0`e_oNF!hy5a)H^H)5)t(}ek4a1Nc~FF4@f;5aO%aB&3O%B8NuMWWCzYb`d> +zQ-&3)G|5M|pzcLy>pA(p=?3&XKn+v0^`HNsS?M0eb+60BxF|&Y{?>MI^x``)Vp}1V +z;<0N$BUc(0=p=y>zD3k_I~ +zMC>T|rn!T!wN%lqT@ +z&Afsj|04$m&CH2M?F|6yeqb+e`&JWTP^~~z(;c>5;z6RuFKe)%3j|YzeZB9c)5E08 +zvX9?L9%?PT7Vu(RAIXR}s*=I*@Qp<*vA{&7B2uwdBH$_I`33U5di9weG|3 +zx-Iy`1L`R>G-q<+w-{f5qc<7ls}^cT4Y^Qi+meHXFIDgqkt0wpdBZGY?LB+q9&o`T +zd18L5%R+44Ml^UNbEw58BXP#{+I#J1$;VGO`#6Grd<=RWgP+T+ktE6H^>C;%(}szj +zK;wt^oW!yG4Fz=zm4zKw@$Wdo`VJm=879kp$F&$uMP_qiKSB4L@SV)g55F9Rb=3ocrK>iqIRR9n!X0Do*Ldi{9M&^sg&T_TZz~>`tbXc$p%%BI% +z#MahUA?U0t#2ZA4_41*w&52#TXU^_G4)$#uGOnpIb{Gs?Bge_xP|beH;cUSBec^gk +zu;a`And#3j5LZ)LALL9lQ0{$A?tzx&K6M(;#M))7n&`7KTkT>KvjI7O4?mTa;X`81yn7WAir6 +z^Dv#2{~#3{X=5gyP*2v`3yoLJl)--n2rC2}*3n8(L~4ohHzT6QbyEu{!K3q#&p9Lp +z?3#RrZR0JWoh5V%Au%m2?uSB&RO!i99khjDd#7P;NaxJ<_f>mYXQOtXqBZifoWn1d5WC&hmG;&Gv(>!l)|)selJ-m-pz9Og@*rA +z%Xl~n+gHI_Rjy513U_dEaq-~ZLm%H7RpVbREoW=Zu*D?n%JFyy6(v}{RCOy +z>_wu--o5bv-4rRuWG0oN3a2+(f)C6nR0%>9HdI1mB`d{jE6Q4vSf>>{@~N-bGMc6~ +zn=1MB2?XIjZuOC!s@-pN5{60UUw-L4f1L-3Ohud?4)I$4Y&#w^A*ij(1$$3|Vskv} +z#YKCOBnHKh5QN8fd|k)wI{^HZj_1!`{L&>R(m@P^tYk*J)5>eCrio9{j>kWLDCGrM +z*O<)utCbjQiH>aHzD!~>SNyzV|B?uyizaR*!v`(g6N5ks=aSqWHk#wzbQOx2Ehc(>s +zfl`oSK+EzLOKDeK?n#pu;5qF1g-8bXyN##%K`x2R14CxOh8w&P-kz4U}>3Q=A& +zwAa>sCXe?|fR^Y+S9_jW;=!_GK`1Bc2HY6Y)*s}A##+#}239~LV&Q~wL&4n_6^@vW +z;nGUYJ$5-C#kJr2EtD&Ty$t-H)#GyT->}39LWB1gdo%LwqR8{YbRBL*-FCEc5iY{; +z#TpZ~y8yolNKuWi&enqz%<*)Y)j#ff)9q1ezkI|N7|zr3b=T|b>+m?)d% +zKJ;1@L~w8ZQn0MxZS*{ew-;Ohn^Jl!+U{m|QvgB~tai**t#d>0E=CMjN*SZ+36QnO +z4NrSN!Cd>9SLf?=!Hjh+ek}c}ND_U`vvi9(MS>7nGZ*lPm%4(7(bhfuTHod8y%;N{YO_KMV}N<7D)x5snD;XG +zzCOH#WK2$4mAvQWFCCZW#F8TRInJ+=$6eR`V~dES6+!6-=6lkVCHyCW^Bb-$@=b%3 +zi%hxQwAp^EOp|zR61~UikJsM89qE@P3@X5J>+K)hO6K`Z$80UqhLV&|mVt3wQ#G4H +zi4>T}s*jr9pkN+B@=LbuMW8^kzEFQde*yOdnXiUws9u#OD8dYzm?0F`qCm7pBCNNz +zOJB@PR!5?2&9Zw_Jg~i=TwmStKiYq1_@$ +zZKB*^u}y2o({7rV#Nl+8$2T5 +zthMF3X`+*;4Q-~&-*4NzrU=7>#}h=jB}<^tsAch7Ac~Vq;V7 +ziknpCHOP}_P8F&VE%6e`WG~EVa?$ra`knKZrYWbIZ_w@4vO+{B!(Pb&!YhY8pCfe= +zjxF8x>Zh3;#gw`fu})grVJcf=Ohg_Xc9m?(57$!NXQ#N%;Q{V}EjtmA$m<@Ie2(h2j9T2Xq=0<2R#daW&$ +z85=lCIqjn+?h$SF4u|?#DOOKg9>2c{9GSdlh{<(WR;Mb+bxH>u95roevUiqSmcdG* +zEL`{Qv+mA#hjLxuC*l?ROBgDsPYkDNU%;m09$2^ni=SVA=kS_) +z_h->URCbhQr89T-a-Gg9Dk?P`CT8-=f%@A28AYMmma&Ks#DNDsr^|eI%nHBQ0Nps* +z<{@u^G-9krSD|^{Vm?_nRkW_T!;E*n95To#4sxn;9FH2W%&T043S^Vg_Bk^^&J9*H +z=-^Zd6GYUG(CMkA?hy<&4Tc5fn4$3ys+ZiGw!07qHH1zPDzAJY;{8Oj#B1-LTAZ>D +zKqX)c%j0#o|H%z2zdkxYKaV6<&nEMgP`q%2&v+2dsa++rFeWoOnf$VkCAY6|8|kw{ +zdwe(maC?oeGlx#HVClH?)W&QZ`+=l3PIeQ%9cb~nWxJ9)YD|MPt`v?0-3bMcbZ<2Z +zG7xSnH{QoOr#C@?R{C$168|JMfCxcPAVuEhewgQpYO@AfbP3Fw+|Vi7h~L@$6ydj5 +zyf7_h9Rp$0Gii0mkT9xddqw>hIVCXV203~$D~swIj_)TV=zX)@-tK6Hb66mM;EywH +zsMV;{!i^8fvae3b)iz7_f6$4yU2i-b%Bh|o@eU2$RD^G(AtWlyl0^8dxd<9 +zCi_xU0%&wFugtmc%-uOk=xMY?lR%{7BQRZ~b8}1<=DQI)v2*#3|70VNVV*?SK4O}0 +z-HEICfCoyTwy@{F=Ac>4KISQEgQLDcj|>j}hzn(*RSn +zZw&u6!^Z2~7ae&u`+{IHYm_vxJJ@RRZ!LoCjQ2ecK6E;AqeyJZxfuAC +zaFBgBIQO4DawgA~vN)BCS%`;S38kn@9kWOTMq)$V$+z&4nDQvH*{(1#N58$C)v2#; +zJW|ch#FaXRBNNj6mX)HNV{_ScADWB7#Jn(Th}B15lvrI|-2fj-=SL1AY +zQrI&y#`tyxRIyenc$G7)m}|d;5&h;8q8?ap1~7v{vEXIAhojO|^XI$6=K!f+>;5yx +zJJXiq*Z?mW;Ak{?4<=)9$$a@6Q*=1_%}Nx&bGA3oqS%{I)k3y{#DALAzrPw)h(FU +zj}8a8Xte($dBpT +z_ZLeg50aO#zhmy?M*+dS#c4NyP>CZSyS+OOi>@2;)lr;&A$)(OEO;kV+bz6O57by +zyW>9>Ij2^Du|A83(r~$46%S7?Ancv(6R +zJK?TL+k$9p$KMJgY}hdrTzyS}0it==hvU?8YM**7M}l@-W{&s26~NM6 +z#U8(RCX-=6Lw%{$D&=aKSfE%aJ<__RASP1DaZcJPva<-yi3NH#t$OuNk6wlp&CD~1 +zanJ|7AhF;l{a^)Qhr_9Bo;2ZG8=}0whx#r7zZ6W`Fs5 +zJEbvhZVJVsORu$w4Y1HyT1E4?Vka&kS*mSpBuKM>OAT~3W;g7KLGzfQWF~QJ1)H6S +zFCOXwP_auqzKSygLBPB}EH;Q1gXb@Wm*lZWfM<8NWGZM_*$8Ze)0+^IpqCyco5T+P +z>!edzc-RMsx%H6~4%a*u{&6!V2Xf)f8oOKEEtBAhvI#TkSv+Ago-TMSQ(2q}=S0FP +zL(1v}1vp6Ya1@zfO!}Dq3ke|~@mmFXu2dHEQWpO$6X$;c8V@V*w>NACSkmSKF-THX +zXc85Wu2(uhx0b@}vaeA-YhO(oJ!8ZlugSxzOn{tnI7h@dCB`UVE~EEY_ww_|qDlb| +zQh0>qvDy{uar91x0J$!N&ch{3*B*?y730`NAZJT0IXU?T1Oo1Zc+QnB&!+ZYLh%_v +zV;)6DQs1sEzvoxu0r{lou-yG%CgwotYzFK>vqr!e>KRehvaz@y)fTge`_wgV2*|2H +zVl|vbxEx$3ymn~uGqN65%FYqJ<_)*Uqs49;KY2h*(Xa?Tk7AFfl-xf>irJoUyL*;0 +z19&1GQV*5Ni~#kTnaq0ymCiLjk_=0q&=&|cG{r57n*6NwV6zJl5K*ED&DsZy8iEL_rr +zgsLXr6cN9-S7dCo0TeKI3ByoGNNBIG{4b4m4=LB^FstU0B?!6TBZ1v~zn%e*Xk=B) +z@_rySE6iHcIxSfbe^sRAkjZKFfR!7A5uNa|Q%HSV{);)`X_I$=Rz#g9)RV +zjIuDE+A6IDHt@Noy^%sCnU|?kL3tCMU12QN7688MFeYr;%^{CT)BqX<4rY8gFNo(^2<+x6~@> +z0Y;8%xJK3sk3si!JoTyNPRqf>i>%mkw_b{g-~}-aAljQww_S1L53kdn=uMDZM5$#ndk +z&22o*u=b&^trc3UMGkzzrL*~$;t?gd{w8WCC+z$)6{fY`v4CL%;?|JZtR3}&oLz8* +zT?G#HsX)xAYvWho@h=pJpzsjcWp0%LD4s08onG)Nb4)MY=8K^XfVvcKVvP||0{idF +zr>Wx=dX&);ID@-|u5Y#BAa0c8rW_t)Xfo4c@By|jKCCPsr7DjJ6t;eTIrmF;CpM`~(ysWB=S@seY-cC;IYp7eGp3%$l} +z)oc?3jDrN<0qs>+yfj#>o^%eHp8`K^wUK{qUM_Xl#K;;VHK+>&$DqLQV1~BoxLuBrt&0}DAhEKn_^ER` +zz-29QNvC|8F%an87xNYKcn*LCu89T8nVkc&?~&O83)5GbY)slt*#=)i7s;A_C=2r7N7+fk`X1KngTDCyUEafq@X5m_z1=DeiD@Q38P{+Ou8AdwgrjC5 +zajlbj!7Ae^jZ~9GGnmvF%|dV*Siz7~1$lG}zFHP5%BV8TD09lQN!w79WRZ;`=PM(z +z0;YT`0PcRb5SM~SQ_OKjwTc~?W_G_IPe||U$;Um2U%fe+7X>%Nvy!xcXUbbT1miw0 +z=$X7_W&m0ay!h~`ae>C68mu@al*ia7R0saqO=sn$tE@ww372nWLhU^>%{WE>Eoln8 +zaeH(5Zly+xlW1Z@B{Z2HqS52V*oh`BC}k&quf19RS}N6$l#0qGWzl9DQkZ@85(#UMH4E) +z!&hPrOmR$HRF*}2C{e3A#U3h9d)gN68^|>O9=TO4Ga~u#5kl0}_*QP9IxEl~Ce;Vj +zS3zvyQ+p-TKYiV8z>J$akDBH=i$W7}&)8|aN%_17$7$H|;eKWRKgAtrMwoyE;#kJp +z>iJ{R+d4p$2q2;Y5EBQ7>@E&mk*MzVW>!EDsQ9Pd1Icl|=0d^U2HU!hP6MLe0bwp2 +zA=U!|OQM?{{^8dU?o^&w|I~Y5fw~zw)IT&*mzBRUy1Ljo^-=Z`fvN|N_JgxG~k*Hc%03VftQZkoi*AD{-11-bt2%}_=-R;7ZY`jOzsFyAEWb! +zVJNLPL#@4|8iv-c@m4Lu!^Uc7?VOsDWty>@T6^QN67|~9P?w&boWVpR2)d)gI@s*$ +zT0uPct)H#x^_Y(_q2El&g2<(pF8niAzCde(;c)XAp3awn@Z)3{qMO$l1?#O_cXL+a +zB+yS96Q;w{xIBw9%-h2xp$%a(D0`Noi$$31BbukCM_lu$4sG_+rWsH9U`eD0eY3t3 +z@`vkyB5OW$_NhyNPE(&_JPvYO1XVd%SiaJPVza|ZguGogD*p`OzJ!Odk4wR7o=G7; +zQFEN*_9WQcO`Vliy5G@VCnZ;Qb~fJ44e1$o^Tw=L_lA;Z-8Dw0CC}X_m5Q_J*xP61 +z2tVQGAnU9PA@k;{9QL{c=-~c_joC`W*8qxTI)7}foE-)SU;g6SD;S1P5oGCta0DrC +zGXz?khB$Fn{Ycwuk%t&RTyJ!Mz8mnC0U+AYu}PkaA-t-gE*25%;RVKNKyWz!scpu6 +zZDKFBX5S4#lCQK!Ip%UxMsP%cC4T!8d`;mo#M{(B)h;Ilk3UVA`-O^+JuQDuUnt-K +z=jEH2NuzvVs7mGT0rJ;Nz54;;pVk-{O`o<8h5~yAG9cx)%sJ+#d0-B8j!9{+{>1@9 +zYiz-m^g@6wE8^*umZD0JhIN!|&Ok-?2XhJ@B|oI&FfS^$rs90JhlZBoJW`e5b9j^- +zWO>uD9oB-o4QKEBn$akVeT1MeUX-s%#m~lPXZR!_h7SU~%Y_rx{QlrO`$o+{oUb!PIS+x5N +z+{O+YLa6?IE1#&A?RMZ&J}!O!vj>Os^y>J_BMi^Cu8;>FP)!5eagStg`4k8`f<9)s +zLv>uniXJHc5tD}2a*xO+UycHT8lGykAS#tq7H&?$Q|yXO#aH{77;M;}%#Rn*u_i#Q#=kFoCjB +zxM)O)sW@_wx=K{lJ|iyESH0iv9Nr111eP3eEA!SenTb%U12{RS*7qj0=;%^Kd#QiJ +ziYTEU=jFY{zWsSqmqmw<7L@5T1o7NxWhht`9gu$(b|QZnjVAE)D;lyC=>~hv=8piE3T9#-QVKCSaq-q&xr*zuRbfKtru+;Kkp5Si5+<6{tz}rp +zigZWmiiYYR#xdxCbhhJz=wN$k9zPcR8H;AJErv2><3*Bm51h&CEJlpT9yo5`1`w{pnaAJ%0k=ISmg0E +zo$J6^H1-w0!^WV5w|yx36dtal`WN}DGpD-gqYjDTfjIaLtR}xxCDSo6v=}KHRM^9@ +z&T;nw5x5ee(K3%Z3QQF%sMId_cIRpr&3g$f><9ZoX7X_c7g4f{y)mf(?;`TLI@jLv +z?N)ryzDJ)LsBZU+VnRH0X1E}KJ!}%#n_-hEY9w +z`8(=7Fd9^wGY;{_ggJK@ZR?yW!1!^^d;F^x%}=DG(7K8XMm$L~K*Np|t>vZmA5%Y| +zINrWxnZFq_J7&ksTGEluekfNRCX$8u^xk+?w8Q1iII^7LA8Wc=uh=>E34C14fN(+~ +zjb&LKSzG|ur8^cG=n*d|U)DK;5`-D7c>o{;1qb8{cYdL5^ll*Y29ag^ZWs(}{Dq?& +z7Vt6fu%BVSoqvD;RYW!I!KS^e-kCz_2@FvAByt<`2mpvxlE{aWp)% +z7->KZs4&!M+Z9|_;(QrbPRGNC2zLU&;bq*v@zaDlNR7 +zR!OB(0w7?XvMI3w1tc_A&fY$=RO&K>9q)K{?KeL9#X2nl`k!ouFF)XFC@Tui*%L4~ +zwNvTu3}=K5TH;uDS!^k3d+!l_hx$f?(hkYU(6NBYx@mz*Y6dZ7D@JF^5^p{aiT5zv +z;Xjc--#|sw407DGZz<4^FBXBq5F)zwTQ|65$~FTfyft2wOiY&QG(ydKoz#wa?YKny +z)9C@EX0c#XN}}K5dNFdMNo^+Os>0sS^c;E5Ky4zm)q;>J{J+z3sdUj)7tN@@gZSf7 +zJ|wiD$oI`e{Xe-gDV9P_(x}i7AaPVJn&m~NMi(84-RGbXy6@{lY?h66ze7!6Ee=i! +zInre-6PCHrI9+8v4+)Zge*esLVEy0*)t)o|)801Zf98hgQ=EZH2bpZ=)5NN_2yjw# +zP8Ewr(5WN{8DJpt*e!|G(gvZ5Pxywag$Agdns%%4+IH>|FMw9b +zKb<-v)*Cb*Ao~hb;B*`Ee&trZYBi`{$ru%gmKbuXcPNb3lD3H3Jimki7;BEFp{bxX +zFJ7Rk<~$d5(AGs1%w=$DDrj&3=?C4wX`U{m8^^=Z8R3YTB_A>ZAOkmldWl +zwo0ZyTNCB`dfUZA+chm*()HWtA2!JQ3>g${8%Vr% +zasf==&095e)fG}M%iIsk{PaQ>2|D59ppz^2pExvb9Ou9EI^`kN!0aXr*u3p0ex0b4 +z=AnHH#@v>`#o*LjN-yB0^^l)H2Nm=yD3|>1aNigv$f`s680kxF8B%d>SUG)YF0R~W +z$TI5rvll2~&q4RSwu3})*@1!~z4l}@NsY#MwV(2Y=hbLZh-ce*Eq3<#rZ +zxra}au9h@`-JaCDeW|)St?N40z`g~4rjZ?xu=?#W;cJyHNPXCV2DuxD%N1A2hAlFH +zwTJm(6XPn#dA&{dq>&yd{5Lp=pa<%$*em=~TdQ%rn_v#5`>I!IS>M^uNpl#N|wC@HMBcRTMT#SL;d7 +z<(&BuA6dLkkx|8fWw@PXzCeCBgDx@HJs@)L+j8y~gZ)7)${p-|O7{G? +z&|M6FI|A*^d_U+Of-3`+w(c~-YsQby|NH)g|G7xv|Nek^|Jex)g~z+)I0xPC0460S +LFIp>X81%mY^Bg|U + +literal 0 +HcmV?d00001 + diff --git a/patches/server/0486-Improve-ServerGUI.patch b/patches/server/0486-Improve-ServerGUI.patch deleted file mode 100644 index 8dde1d1a9b..0000000000 --- a/patches/server/0486-Improve-ServerGUI.patch +++ /dev/null @@ -1,431 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: AlexProgrammerDE <40795980+AlexProgrammerDE@users.noreply.github.com> -Date: Sat, 3 Oct 2020 08:27:40 +0200 -Subject: [PATCH] Improve ServerGUI - -- Added logo to server frame -- Show tps in the server stats - -diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java -index f93373d28d741e1f8a53e07b4e328ce9c4e1657f..12b327eea95e0de9e9c39b7d039badee8ec46508 100644 ---- a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java -+++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java -@@ -58,9 +58,22 @@ public class RAMDetails extends JList { - public void update() { - GraphData data = RAMGraph.DATA.peekLast(); - Vector vector = new Vector<>(); -+ -+ // Follows CraftServer#getTPS -+ double[] tps = new double[] { -+ server.tps1.getAverage(), -+ server.tps5.getAverage(), -+ server.tps15.getAverage() -+ }; -+ String[] tpsAvg = new String[tps.length]; -+ -+ for ( int g = 0; g < tps.length; g++) { -+ tpsAvg[g] = format( tps[g] ); -+ } - vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)"); - vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb"); - vector.add("Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms"); -+ vector.add("TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg)); - setListData(vector); - } - -@@ -71,4 +84,8 @@ public class RAMDetails extends JList { - } - return ((double) total / (double) tickTimes.length) * 1.0E-6D; - } -+ -+ private static String format(double tps) { -+ return ( ( tps > 21.0 ) ? "*" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 ); -+ } - } -diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java -index 8b570b0c3967a22c085f390110cb29cbd9c8feff..4d3fe4f56e0b264fa030409919caf52d5f421d46 100644 ---- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java -+++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java -@@ -59,6 +59,15 @@ public class MinecraftServerGui extends JComponent { - jframe.pack(); - jframe.setLocationRelativeTo((Component) null); - jframe.setVisible(true); -+ jframe.setName("Minecraft server"); // Paper - Improve ServerGUI -+ -+ // Paper start - Improve ServerGUI -+ try { -+ jframe.setIconImage(javax.imageio.ImageIO.read(Objects.requireNonNull(MinecraftServerGui.class.getClassLoader().getResourceAsStream("logo.png")))); -+ } catch (java.io.IOException ignore) { -+ } -+ // Paper end - Improve ServerGUI -+ - jframe.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent windowevent) { - if (!servergui.isClosing.getAndSet(true)) { -diff --git a/src/main/java/net/minecraft/server/gui/StatsComponent.java b/src/main/java/net/minecraft/server/gui/StatsComponent.java -index 6e9c6d556ed55325e36d191fc9d1508c00879671..096c89bd01cec2abd151bf6fffc4847d1bcd548f 100644 ---- a/src/main/java/net/minecraft/server/gui/StatsComponent.java -+++ b/src/main/java/net/minecraft/server/gui/StatsComponent.java -@@ -34,10 +34,19 @@ public class StatsComponent extends JComponent { - - private void tick() { - long l = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); -+ // Paper start - Improve ServerGUI -+ double[] tps = org.bukkit.Bukkit.getTPS(); -+ String[] tpsAvg = new String[tps.length]; -+ -+ for ( int g = 0; g < tps.length; g++) { -+ tpsAvg[g] = format( tps[g] ); -+ } - this.msgs[0] = "Memory use: " + l / 1024L / 1024L + " mb (" + Runtime.getRuntime().freeMemory() * 100L / Runtime.getRuntime().maxMemory() + "% free)"; - this.msgs[1] = "Avg tick: " - + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double)TimeUtil.NANOSECONDS_PER_MILLISECOND) - + " ms"; -+ this.msgs[2] = "TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg); -+ // Paper end - Improve ServerGUI - this.values[this.vp++ & 0xFF] = (int)(l * 100L / Runtime.getRuntime().maxMemory()); - this.repaint(); - } -@@ -66,4 +75,10 @@ public class StatsComponent extends JComponent { - public void close() { - this.timer.stop(); - } -+ -+ // Paper start - Improve ServerGUI -+ private static String format(double tps) { -+ return (( tps > 21.0 ) ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0); // only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise -+ } -+ // Paper end - Improve ServerGUI - } -diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png -new file mode 100644 -index 0000000000000000000000000000000000000000..8b924977b7886df9ab8790b1e4ff9b1c04a2af45 -GIT binary patch -literal 16900 -zcmaicV|1Ng^k&Q(Hn!T>_Kj`Zc4OO48rwD-Gw*(Xv_UIGaL4*?7e3`t5-R2lSh^xqd84Cs4}W^FDQn9zijsF13M{zVR~<`0dB -z;hww3Rk_uLO*yyZ^N(arMN#SjFcHEi60E_fZug`IjtJ^LVtno=lKj+Jze{_WszRIN1X*HUTCH>C_wc;+D)6YYT -z*RWmTUi`Puu_Uwkj6-qwu_Ue*kO&$%=o%J?6*rej_Ock3znkGIb6 -zWm&yS2Z9LS7slFgUx+?ilDgQBdj7`ruw|IVzJ@wV{&tD)G@SPTMW@9Wl5lcsuU~6` -z7raw|%Or|@Pnlh`7!!rA1H$`p;zz}+92Tp2bFmKDAL`nrC>)<{qBHso -zvJ6|o^vMxL?frh4XZ`3WdH7s_NI0p@{EElbnX*!yp;Vtx&K&w$&to`sW -z79>enm;xWhu;ZKKIN}-h!eBKZM6j$9~*Q(SlE*i_bHS0o#tPY -z5-j+ww|x>h9%`RLUixM!e%f0qVAe5GH83X6?!#^_j-M@lO@*-aD%NMF2;Hg^Wgh@}elrPA3o_&(- -zeNyws4es~%;K1o+pfG(Z!G-nFWzl7)ejRNxY?M~uI=I&MYuz@4>GLH*ptjlQJ`LYr -z*KIIVzBhKHIDwe`X2hc@gsdjzXxX%b<_#kc$vIHFi2)-XM1=fs(`g?0)M{lcJXwp< -zBgIdDXM&n-=+_%;1a?sE$oeN{r%w=8tFfAlQopAk -z%wrVN=r>)oZ0w7^M~Xi~qp6lEaABgF(ck7V3Un;@cg|ODuD7@fw~OZ;^TQV -z$&4AiUj}-4;o`6JV$Y4C2G -z8hVweUdzl78hWzD|&J_)oRr2JdJP -zA&lca);^P(q@hQb9-kqNXVo9An7Q3NoAtyRQw-@JUDD$oluryjE -z3{zzbZhStP-K;xw@Yxf-B=4h(p=4f`k8p2DH$>qQLPR!szD!2|vJ}J`C6=EoRwG^+ -z;`ZDv1SGVO+?IqSxpxSM^_V~@2E+~dZQdl+oz;TP1MX+XXwugMy?Z5AoZ7#R33Y@T -zM)w4;9L0szO3>6i#4fV3q49@wu&`zcvQ!d8!m*dpn&7pp0Y=;QbiyOzhC7)Ki7tDt -zXaIqysWqx53ZgHlO)|YRDG**$7&F{0a8VEECY`3;yx)F>2;4Xr&gC;Iqiqx;orWkF -z8xk0Ty-mK&z`^~Fbs#S;;Qd@1ZFJh4R`+H>Wx$xgn>^oka;w9~QfR>rS7lYHG?D#o -z6Jo`Qg_-DP -zX@kdURs~L5?afF*73QF!=HQ?vIysP;FNCMBfA*}*&%$eDHh5L|y~D=C^v8(wdtcYZ -z)8Q|56BuZ~3~KpF-oKg|5Uf@Ac15Z>sP<9hpm(E>^cgr8dMxGhn7mnWA+JPK+EGR; -zCfK+V1&Xi1M6CUFIA+oJqr(aF3W_=ph7h;IVlqq&xJ=d(CqczQwL>f*A$gJW_|iZw -z&>!^cGyI)UH(_%jFMta0ci8K;?^D#C4_`@%@wP6R4qvs8y@ecdj|*ia7Exg3*BpG4 -z%Dqav(-_hWolzv04-3Ygs)Z~U$`R?hQq2Is2`RWS%z4?!GF2CryzMjCEFg_Y%K+yz -zG8tm;0X{;XG5?BBT|pMZ296(fGUtoF_$Ryrso&s;Cc!g3a;pYOn-tjPvW+1)iAQ)I -zaPyG(wl0MZUqz_Z!4+oEh$t>QIaiZ+J1|fQdfugliOCAg+6D!~3<-k#gA8N#Rk3@5 -z&u3Yevetsi3m`sm2Ntt>FV(PfME~wR=LFu+2@Noy&wr###hgP3mjy&H03re#97OQ% -zsZ;NtktNoC?s@G44Num-@G1zw*?jMf)dA`SWJHyI-Lp=m -zyv8V97L8$~?>Sf(&Ee27TQvEf=-_%~EL56_n`*ZRVS`=4Ka4&HGjr9P8e3rf;8BK& -z&0s~H!Z|V-mPt9vUj?5&%Sa@;XK~`TS$ylgW4|1h&I!<9c6_zoDdR2)FLErHw%Sow -zwc_2ZKizcAMchMvZ^6OY8)uiUt&RwA(`3@dzgihQ1MSrNi;ruq-C+?oVa@U0x -z(>^4ei3Bedg+!LX52G(u@W4P&3sdv45%OawU(*aQat~OuEf?Hi6Zi>__qCd)nw0_j -zvUwA_6WQ5tnFsl_AZNz8L8L*=L4?0A>inj9l&C`AC71u=H -z?bu{Q_=al@1+|F&El|te2eQB@?#+g(D(LjFx>w=0X;CJ|CQc@tuin_)Rd$KH$Y9P9 -z${MAq+Ns2`>_SLAfKm9~%?U2bK6>hiDEbdUD#NMd$hR*wFx8TxWVY3Za -zM&tRPhR$htT-*KlZT-SGBy4YD;6aZfAz^Jt1`=ABifztn#D_;u)2WTa-Bo^EKL;=o -zDc6Ov2x3ybU1B6gkFjv-UvyFl^(EFkIb4ht2Z(*io4 -zW(6^Rp7OMxVh73mYH?bkbxgXB=+TL>U^8OY>=P$oXPkGAmF?6#80T -z+e?24uzuJC8?nCu`7)ef&Nu8x+`0%wOB9wmZ^(+|&$!T80~3uj?NRH)aNhf~#vN9e -zem1VW#bKd$SZ4ufS0-pzoJ%P7UWdT@8yg`1+kpYLV153t;UJy~P8@7sO+#{ePIXcSgw}v2XayA<>Jxh}D)tMOGRgJY0QEJs` -z{>aB;ssVeqKi-6L#(PnBpPuOu<4Rf*GWVk8BdMCd} -zc^_!LU3n2YWBEk1?0<%f@MkB;t#h0%&cixNCZn@Lft$eDVl6z=l@Ga}k<7cF5n!!o -zXet^Q3;AyG!j)+$=3U>7D5cEf)=YMZ)jSZ?)!6EoSa3kU!3W2Xn`K`PqR|ML`Ju!A)|K2`l1>ErJG>o*qIC72B&jHYe36od@P! -zi)qQ9Y7g*>N;Y4;sSLlPxvM;q-Tzw2m;Zx=x>{mk0;Ed5zA?Hb1FrDGc6-;m+iSFU -zc22aC&R^-iyw5vE$D?GWWo7A5o@@>d3_uD92sGM_-tlsdQ?ZbAnF4LsSxDj&0TFgO -zFbB*@;0<;Y0es>tB&~M12_up)gRS(Ce{seFR$9$~MC8~S%gCTV+2AIiH`gndEW2~H -z`z|RK5KuxIccy|!;Bkm8puw0EcWFE{ij71G*o4( -z0~y!3%z_nq1kdh3x<;XVQS{_v?Q3|H1so1Z#CL|Zm2Z&7-mTO?&1?U-oogOAE4Cm{ -z`d4o(XCnWH-J^hx&?7X^xHns&B`u2*skUy`s~w=0252bVaZy(}U?e5?u>fG!UbYaS -z4Gz$YBX|~|U$??YUR+zxw2g5F_OJB7viI^}qx|ouEswnc0o{D4T~~|912EVr9)4P& -zS=*@uBmgy>GC)sz_8A$Iga2y-R#LKP$zyVe7P=4Vrn@Q)Fp6mG;Nall=^07<{OPT~ -zPDD~5M}Py>^H&ikOMCrXaXjFMyNuyNg$gXaPOE4z3=$o3Jt(guFuvAQbA?*MR;Dx}r~+zsgJ -zzCtQ*$r?UAKNl$E39K|(pdcV17*;zU{VtG7{)QDicnC&XAit07AxkJs2xbNxkEh-l -ztI=-hZ#0{5e0{huHk5pMKFXUdk-_HT=8j~#**>ze%L-Vq--ELbc7OqlEqqgfDL$7| -z^zia3^m~7il#>&4bK{s6W!C%o9eQ_nw_LRXoq&)qk2e`~Carh!_+@C+^?4E@nB?8v -zrP(B~aF_-3_5wx4#3EgX2f|T2iDX6dBot9e+}zxz-+7y;fop?^#LWumnJ%(ER<|F> -z44(0)x_-m7iZI17bV#w5<;|{V>IZ-R+z|XI2d!L0M$z{_~PzI|b} -z_>I9TkwT-USfkDEyuoB7YJe7^SUeW*JCd>d31w)Viag>w -zE)Hcnu_U(A@CEh^w;UM0IVsDf+yNUB)lCpiM=a>2dMSVx95URpuHBLGh>h8fgM&77%eeba~6*@>lA8=;7iEw2QP4d^IvP -z8fpiWc?lq5kxp*C)nS|HY^i2ov(x?A!{1u(mk%xyJ_nmAsx{Zt=LV=Ta0-O}2|y4O -z5yIAhMw5|xp3lvw|Ps$0W*KZd^Wlj=W@{AaG=^es3_){Y~Jis`IYYiWN~ho|DLil1qRD5 -zN6xAlvXG=U-8`VKVHr!k-;5Bi)EfnJRTtvY$;jR$#e%~lxMV?xboY;JA{IT_^y}D0 -zw1mJ8tVoSO-(}absB6M8b$Zqe)Ok0$OkaA#I -z48@e8TAlv;PmB6dbP|{7<%qt@Ea>I;PRL4)=M`_G!A40Y$Xy1Mum)I0#!3<77H4)u -zI6c{)TUsy&o^*@2H9Bp>QJA#S8$`zN?+@z^IIQL|VxYEQfVw~Oc}Wq!FS`G2T=aDu -z-DMYe(1$x=331oN(i#yV%?Q)lcY`}FpGRp*74@@$fX%pE+dAGOh5QRhJ&mcaXOhk4 -zLi_pirw^Zws;d9n^#IE8T1ypZDX|crNABquU?iL2;Ql%4Vg5cNBt}OJdbLKnEi|`g2q%v70%eM&7 -z5gdFefu8Ix3n54MC -zW40SGT11ajrrm5AI24T?-2$|VMsU%VX}AMmt>Pr~B}#An{>%QG>_1FQYV^)CExzx2 -z&7E_9c!fpiCLci|F3H*eM2DQQRtQp4>V2RP=KX3ZVw#OXuFxj$VDmM&HQD{*dc7301976VQyI69%EFvxxn>qC&Lo-`%ImvM -zCv>AXKPcD26Z_;m`1pw)uF6Mp=RnShU^yM81!?jbl!v#-kSa#RLhSOG0?yp1YB6Jr -zW=GrO|0zIRSHiH?DYiO+$EpdMkwz#4I6V(J12-W0+dAo4J*?nDQrFI<*}a92Y%1bU -z`RC_4tyg7>R(8{ -zA8*g?PWv##WoF+p0bJe>whg#+(1_+A+)9HS$|n?k;(r=Le*vR;57rn)2& -zEkD8KBSZm#3Drt?t!*#s#>0+yUNysIKRg=t`KSOcSHieiUP0z8F_$tZ(ciPnq_o~@ -z%-{zhbs{i7 -zt~8q8%WO|MF(FE_ye*bl_-@NcA!S9$IMb6x0`e_oNF!hy5a)H^H)5)t(}ek4a1Nc~FF4@f;5aO%aB&3O%B8NuMWWCzYb`d> -zQ-&3)G|5M|pzcLy>pA(p=?3&XKn+v0^`HNsS?M0eb+60BxF|&Y{?>MI^x``)Vp}1V -z;<0N$BUc(0=p=y>zD3k_I~ -zMC>T|rn!T!wN%lqT@ -z&Afsj|04$m&CH2M?F|6yeqb+e`&JWTP^~~z(;c>5;z6RuFKe)%3j|YzeZB9c)5E08 -zvX9?L9%?PT7Vu(RAIXR}s*=I*@Qp<*vA{&7B2uwdBH$_I`33U5di9weG|3 -zx-Iy`1L`R>G-q<+w-{f5qc<7ls}^cT4Y^Qi+meHXFIDgqkt0wpdBZGY?LB+q9&o`T -zd18L5%R+44Ml^UNbEw58BXP#{+I#J1$;VGO`#6Grd<=RWgP+T+ktE6H^>C;%(}szj -zK;wt^oW!yG4Fz=zm4zKw@$Wdo`VJm=879kp$F&$uMP_qiKSB4L@SV)g55F9Rb=3ocrK>iqIRR9n!X0Do*Ldi{9M&^sg&T_TZz~>`tbXc$p%%BI% -z#MahUA?U0t#2ZA4_41*w&52#TXU^_G4)$#uGOnpIb{Gs?Bge_xP|beH;cUSBec^gk -zu;a`And#3j5LZ)LALL9lQ0{$A?tzx&K6M(;#M))7n&`7KTkT>KvjI7O4?mTa;X`81yn7WAir6 -z^Dv#2{~#3{X=5gyP*2v`3yoLJl)--n2rC2}*3n8(L~4ohHzT6QbyEu{!K3q#&p9Lp -z?3#RrZR0JWoh5V%Au%m2?uSB&RO!i99khjDd#7P;NaxJ<_f>mYXQOtXqBZifoWn1d5WC&hmG;&Gv(>!l)|)selJ-m-pz9Og@*rA -z%Xl~n+gHI_Rjy513U_dEaq-~ZLm%H7RpVbREoW=Zu*D?n%JFyy6(v}{RCOy -z>_wu--o5bv-4rRuWG0oN3a2+(f)C6nR0%>9HdI1mB`d{jE6Q4vSf>>{@~N-bGMc6~ -zn=1MB2?XIjZuOC!s@-pN5{60UUw-L4f1L-3Ohud?4)I$4Y&#w^A*ij(1$$3|Vskv} -z#YKCOBnHKh5QN8fd|k)wI{^HZj_1!`{L&>R(m@P^tYk*J)5>eCrio9{j>kWLDCGrM -z*O<)utCbjQiH>aHzD!~>SNyzV|B?uyizaR*!v`(g6N5ks=aSqWHk#wzbQOx2Ehc(>s -zfl`oSK+EzLOKDeK?n#pu;5qF1g-8bXyN##%K`x2R14CxOh8w&P-kz4U}>3Q=A& -zwAa>sCXe?|fR^Y+S9_jW;=!_GK`1Bc2HY6Y)*s}A##+#}239~LV&Q~wL&4n_6^@vW -z;nGUYJ$5-C#kJr2EtD&Ty$t-H)#GyT->}39LWB1gdo%LwqR8{YbRBL*-FCEc5iY{; -z#TpZ~y8yolNKuWi&enqz%<*)Y)j#ff)9q1ezkI|N7|zr3b=T|b>+m?)d% -zKJ;1@L~w8ZQn0MxZS*{ew-;Ohn^Jl!+U{m|QvgB~tai**t#d>0E=CMjN*SZ+36QnO -z4NrSN!Cd>9SLf?=!Hjh+ek}c}ND_U`vvi9(MS>7nGZ*lPm%4(7(bhfuTHod8y%;N{YO_KMV}N<7D)x5snD;XG -zzCOH#WK2$4mAvQWFCCZW#F8TRInJ+=$6eR`V~dES6+!6-=6lkVCHyCW^Bb-$@=b%3 -zi%hxQwAp^EOp|zR61~UikJsM89qE@P3@X5J>+K)hO6K`Z$80UqhLV&|mVt3wQ#G4H -zi4>T}s*jr9pkN+B@=LbuMW8^kzEFQde*yOdnXiUws9u#OD8dYzm?0F`qCm7pBCNNz -zOJB@PR!5?2&9Zw_Jg~i=TwmStKiYq1_@$ -zZKB*^u}y2o({7rV#Nl+8$2T5 -zthMF3X`+*;4Q-~&-*4NzrU=7>#}h=jB}<^tsAch7Ac~Vq;V7 -ziknpCHOP}_P8F&VE%6e`WG~EVa?$ra`knKZrYWbIZ_w@4vO+{B!(Pb&!YhY8pCfe= -zjxF8x>Zh3;#gw`fu})grVJcf=Ohg_Xc9m?(57$!NXQ#N%;Q{V}EjtmA$m<@Ie2(h2j9T2Xq=0<2R#daW&$ -z85=lCIqjn+?h$SF4u|?#DOOKg9>2c{9GSdlh{<(WR;Mb+bxH>u95roevUiqSmcdG* -zEL`{Qv+mA#hjLxuC*l?ROBgDsPYkDNU%;m09$2^ni=SVA=kS_) -z_h->URCbhQr89T-a-Gg9Dk?P`CT8-=f%@A28AYMmma&Ks#DNDsr^|eI%nHBQ0Nps* -z<{@u^G-9krSD|^{Vm?_nRkW_T!;E*n95To#4sxn;9FH2W%&T043S^Vg_Bk^^&J9*H -z=-^Zd6GYUG(CMkA?hy<&4Tc5fn4$3ys+ZiGw!07qHH1zPDzAJY;{8Oj#B1-LTAZ>D -zKqX)c%j0#o|H%z2zdkxYKaV6<&nEMgP`q%2&v+2dsa++rFeWoOnf$VkCAY6|8|kw{ -zdwe(maC?oeGlx#HVClH?)W&QZ`+=l3PIeQ%9cb~nWxJ9)YD|MPt`v?0-3bMcbZ<2Z -zG7xSnH{QoOr#C@?R{C$168|JMfCxcPAVuEhewgQpYO@AfbP3Fw+|Vi7h~L@$6ydj5 -zyf7_h9Rp$0Gii0mkT9xddqw>hIVCXV203~$D~swIj_)TV=zX)@-tK6Hb66mM;EywH -zsMV;{!i^8fvae3b)iz7_f6$4yU2i-b%Bh|o@eU2$RD^G(AtWlyl0^8dxd<9 -zCi_xU0%&wFugtmc%-uOk=xMY?lR%{7BQRZ~b8}1<=DQI)v2*#3|70VNVV*?SK4O}0 -z-HEICfCoyTwy@{F=Ac>4KISQEgQLDcj|>j}hzn(*RSn -zZw&u6!^Z2~7ae&u`+{IHYm_vxJJ@RRZ!LoCjQ2ecK6E;AqeyJZxfuAC -zaFBgBIQO4DawgA~vN)BCS%`;S38kn@9kWOTMq)$V$+z&4nDQvH*{(1#N58$C)v2#; -zJW|ch#FaXRBNNj6mX)HNV{_ScADWB7#Jn(Th}B15lvrI|-2fj-=SL1AY -zQrI&y#`tyxRIyenc$G7)m}|d;5&h;8q8?ap1~7v{vEXIAhojO|^XI$6=K!f+>;5yx -zJJXiq*Z?mW;Ak{?4<=)9$$a@6Q*=1_%}Nx&bGA3oqS%{I)k3y{#DALAzrPw)h(FU -zj}8a8Xte($dBpT -z_ZLeg50aO#zhmy?M*+dS#c4NyP>CZSyS+OOi>@2;)lr;&A$)(OEO;kV+bz6O57by -zyW>9>Ij2^Du|A83(r~$46%S7?Ancv(6R -zJK?TL+k$9p$KMJgY}hdrTzyS}0it==hvU?8YM**7M}l@-W{&s26~NM6 -z#U8(RCX-=6Lw%{$D&=aKSfE%aJ<__RASP1DaZcJPva<-yi3NH#t$OuNk6wlp&CD~1 -zanJ|7AhF;l{a^)Qhr_9Bo;2ZG8=}0whx#r7zZ6W`Fs5 -zJEbvhZVJVsORu$w4Y1HyT1E4?Vka&kS*mSpBuKM>OAT~3W;g7KLGzfQWF~QJ1)H6S -zFCOXwP_auqzKSygLBPB}EH;Q1gXb@Wm*lZWfM<8NWGZM_*$8Ze)0+^IpqCyco5T+P -z>!edzc-RMsx%H6~4%a*u{&6!V2Xf)f8oOKEEtBAhvI#TkSv+Ago-TMSQ(2q}=S0FP -zL(1v}1vp6Ya1@zfO!}Dq3ke|~@mmFXu2dHEQWpO$6X$;c8V@V*w>NACSkmSKF-THX -zXc85Wu2(uhx0b@}vaeA-YhO(oJ!8ZlugSxzOn{tnI7h@dCB`UVE~EEY_ww_|qDlb| -zQh0>qvDy{uar91x0J$!N&ch{3*B*?y730`NAZJT0IXU?T1Oo1Zc+QnB&!+ZYLh%_v -zV;)6DQs1sEzvoxu0r{lou-yG%CgwotYzFK>vqr!e>KRehvaz@y)fTge`_wgV2*|2H -zVl|vbxEx$3ymn~uGqN65%FYqJ<_)*Uqs49;KY2h*(Xa?Tk7AFfl-xf>irJoUyL*;0 -z19&1GQV*5Ni~#kTnaq0ymCiLjk_=0q&=&|cG{r57n*6NwV6zJl5K*ED&DsZy8iEL_rr -zgsLXr6cN9-S7dCo0TeKI3ByoGNNBIG{4b4m4=LB^FstU0B?!6TBZ1v~zn%e*Xk=B) -z@_rySE6iHcIxSfbe^sRAkjZKFfR!7A5uNa|Q%HSV{);)`X_I$=Rz#g9)RV -zjIuDE+A6IDHt@Noy^%sCnU|?kL3tCMU12QN7688MFeYr;%^{CT)BqX<4rY8gFNo(^2<+x6~@> -z0Y;8%xJK3sk3si!JoTyNPRqf>i>%mkw_b{g-~}-aAljQww_S1L53kdn=uMDZM5$#ndk -z&22o*u=b&^trc3UMGkzzrL*~$;t?gd{w8WCC+z$)6{fY`v4CL%;?|JZtR3}&oLz8* -zT?G#HsX)xAYvWho@h=pJpzsjcWp0%LD4s08onG)Nb4)MY=8K^XfVvcKVvP||0{idF -zr>Wx=dX&);ID@-|u5Y#BAa0c8rW_t)Xfo4c@By|jKCCPsr7DjJ6t;eTIrmF;CpM`~(ysWB=S@seY-cC;IYp7eGp3%$l} -z)oc?3jDrN<0qs>+yfj#>o^%eHp8`K^wUK{qUM_Xl#K;;VHK+>&$DqLQV1~BoxLuBrt&0}DAhEKn_^ER` -zz-29QNvC|8F%an87xNYKcn*LCu89T8nVkc&?~&O83)5GbY)slt*#=)i7s;A_C=2r7N7+fk`X1KngTDCyUEafq@X5m_z1=DeiD@Q38P{+Ou8AdwgrjC5 -zajlbj!7Ae^jZ~9GGnmvF%|dV*Siz7~1$lG}zFHP5%BV8TD09lQN!w79WRZ;`=PM(z -z0;YT`0PcRb5SM~SQ_OKjwTc~?W_G_IPe||U$;Um2U%fe+7X>%Nvy!xcXUbbT1miw0 -z=$X7_W&m0ay!h~`ae>C68mu@al*ia7R0saqO=sn$tE@ww372nWLhU^>%{WE>Eoln8 -zaeH(5Zly+xlW1Z@B{Z2HqS52V*oh`BC}k&quf19RS}N6$l#0qGWzl9DQkZ@85(#UMH4E) -z!&hPrOmR$HRF*}2C{e3A#U3h9d)gN68^|>O9=TO4Ga~u#5kl0}_*QP9IxEl~Ce;Vj -zS3zvyQ+p-TKYiV8z>J$akDBH=i$W7}&)8|aN%_17$7$H|;eKWRKgAtrMwoyE;#kJp -z>iJ{R+d4p$2q2;Y5EBQ7>@E&mk*MzVW>!EDsQ9Pd1Icl|=0d^U2HU!hP6MLe0bwp2 -zA=U!|OQM?{{^8dU?o^&w|I~Y5fw~zw)IT&*mzBRUy1Ljo^-=Z`fvN|N_JgxG~k*Hc%03VftQZkoi*AD{-11-bt2%}_=-R;7ZY`jOzsFyAEWb! -zVJNLPL#@4|8iv-c@m4Lu!^Uc7?VOsDWty>@T6^QN67|~9P?w&boWVpR2)d)gI@s*$ -zT0uPct)H#x^_Y(_q2El&g2<(pF8niAzCde(;c)XAp3awn@Z)3{qMO$l1?#O_cXL+a -zB+yS96Q;w{xIBw9%-h2xp$%a(D0`Noi$$31BbukCM_lu$4sG_+rWsH9U`eD0eY3t3 -z@`vkyB5OW$_NhyNPE(&_JPvYO1XVd%SiaJPVza|ZguGogD*p`OzJ!Odk4wR7o=G7; -zQFEN*_9WQcO`Vliy5G@VCnZ;Qb~fJ44e1$o^Tw=L_lA;Z-8Dw0CC}X_m5Q_J*xP61 -z2tVQGAnU9PA@k;{9QL{c=-~c_joC`W*8qxTI)7}foE-)SU;g6SD;S1P5oGCta0DrC -zGXz?khB$Fn{Ycwuk%t&RTyJ!Mz8mnC0U+AYu}PkaA-t-gE*25%;RVKNKyWz!scpu6 -zZDKFBX5S4#lCQK!Ip%UxMsP%cC4T!8d`;mo#M{(B)h;Ilk3UVA`-O^+JuQDuUnt-K -z=jEH2NuzvVs7mGT0rJ;Nz54;;pVk-{O`o<8h5~yAG9cx)%sJ+#d0-B8j!9{+{>1@9 -zYiz-m^g@6wE8^*umZD0JhIN!|&Ok-?2XhJ@B|oI&FfS^$rs90JhlZBoJW`e5b9j^- -zWO>uD9oB-o4QKEBn$akVeT1MeUX-s%#m~lPXZR!_h7SU~%Y_rx{QlrO`$o+{oUb!PIS+x5N -z+{O+YLa6?IE1#&A?RMZ&J}!O!vj>Os^y>J_BMi^Cu8;>FP)!5eagStg`4k8`f<9)s -zLv>uniXJHc5tD}2a*xO+UycHT8lGykAS#tq7H&?$Q|yXO#aH{77;M;}%#Rn*u_i#Q#=kFoCjB -zxM)O)sW@_wx=K{lJ|iyESH0iv9Nr111eP3eEA!SenTb%U12{RS*7qj0=;%^Kd#QiJ -ziYTEU=jFY{zWsSqmqmw<7L@5T1o7NxWhht`9gu$(b|QZnjVAE)D;lyC=>~hv=8piE3T9#-QVKCSaq-q&xr*zuRbfKtru+;Kkp5Si5+<6{tz}rp -zigZWmiiYYR#xdxCbhhJz=wN$k9zPcR8H;AJErv2><3*Bm51h&CEJlpT9yo5`1`w{pnaAJ%0k=ISmg0E -zo$J6^H1-w0!^WV5w|yx36dtal`WN}DGpD-gqYjDTfjIaLtR}xxCDSo6v=}KHRM^9@ -z&T;nw5x5ee(K3%Z3QQF%sMId_cIRpr&3g$f><9ZoX7X_c7g4f{y)mf(?;`TLI@jLv -z?N)ryzDJ)LsBZU+VnRH0X1E}KJ!}%#n_-hEY9w -z`8(=7Fd9^wGY;{_ggJK@ZR?yW!1!^^d;F^x%}=DG(7K8XMm$L~K*Np|t>vZmA5%Y| -zINrWxnZFq_J7&ksTGEluekfNRCX$8u^xk+?w8Q1iII^7LA8Wc=uh=>E34C14fN(+~ -zjb&LKSzG|ur8^cG=n*d|U)DK;5`-D7c>o{;1qb8{cYdL5^ll*Y29ag^ZWs(}{Dq?& -z7Vt6fu%BVSoqvD;RYW!I!KS^e-kCz_2@FvAByt<`2mpvxlE{aWp)% -z7->KZs4&!M+Z9|_;(QrbPRGNC2zLU&;bq*v@zaDlNR7 -zR!OB(0w7?XvMI3w1tc_A&fY$=RO&K>9q)K{?KeL9#X2nl`k!ouFF)XFC@Tui*%L4~ -zwNvTu3}=K5TH;uDS!^k3d+!l_hx$f?(hkYU(6NBYx@mz*Y6dZ7D@JF^5^p{aiT5zv -z;Xjc--#|sw407DGZz<4^FBXBq5F)zwTQ|65$~FTfyft2wOiY&QG(ydKoz#wa?YKny -z)9C@EX0c#XN}}K5dNFdMNo^+Os>0sS^c;E5Ky4zm)q;>J{J+z3sdUj)7tN@@gZSf7 -zJ|wiD$oI`e{Xe-gDV9P_(x}i7AaPVJn&m~NMi(84-RGbXy6@{lY?h66ze7!6Ee=i! -zInre-6PCHrI9+8v4+)Zge*esLVEy0*)t)o|)801Zf98hgQ=EZH2bpZ=)5NN_2yjw# -zP8Ewr(5WN{8DJpt*e!|G(gvZ5Pxywag$Agdns%%4+IH>|FMw9b -zKb<-v)*Cb*Ao~hb;B*`Ee&trZYBi`{$ru%gmKbuXcPNb3lD3H3Jimki7;BEFp{bxX -zFJ7Rk<~$d5(AGs1%w=$DDrj&3=?C4wX`U{m8^^=Z8R3YTB_A>ZAOkmldWl -zwo0ZyTNCB`dfUZA+chm*()HWtA2!JQ3>g${8%Vr% -zasf==&095e)fG}M%iIsk{PaQ>2|D59ppz^2pExvb9Ou9EI^`kN!0aXr*u3p0ex0b4 -z=AnHH#@v>`#o*LjN-yB0^^l)H2Nm=yD3|>1aNigv$f`s680kxF8B%d>SUG)YF0R~W -z$TI5rvll2~&q4RSwu3})*@1!~z4l}@NsY#MwV(2Y=hbLZh-ce*Eq3<#rZ -zxra}au9h@`-JaCDeW|)St?N40z`g~4rjZ?xu=?#W;cJyHNPXCV2DuxD%N1A2hAlFH -zwTJm(6XPn#dA&{dq>&yd{5Lp=pa<%$*em=~TdQ%rn_v#5`>I!IS>M^uNpl#N|wC@HMBcRTMT#SL;d7 -z<(&BuA6dLkkx|8fWw@PXzCeCBgDx@HJs@)L+j8y~gZ)7)${p-|O7{G? -z&|M6FI|A*^d_U+Of-3`+w(c~-YsQby|NH)g|G7xv|Nek^|Jex)g~z+)I0xPC0460S -LFIp>X81%mY^Bg|U - -literal 0 -HcmV?d00001 - diff --git a/patches/server/0486-fix-converting-txt-to-json-file.patch b/patches/server/0486-fix-converting-txt-to-json-file.patch new file mode 100644 index 0000000000..b71e73914b --- /dev/null +++ b/patches/server/0486-fix-converting-txt-to-json-file.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 4 Jan 2021 19:49:15 -0800 +Subject: [PATCH] fix converting txt to json file + + +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java +index 929f59bce01c8e6ed4b0b551744d42e131b8fc80..22c4f8dea99f92a1eb3da2baf0a15bf9d2ca0462 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java +@@ -18,6 +18,11 @@ public class DedicatedPlayerList extends PlayerList { + this.setViewDistance(dedicatedServerProperties.viewDistance); + this.setSimulationDistance(dedicatedServerProperties.simulationDistance); + super.setUsingWhiteList(dedicatedServerProperties.whiteList.get()); ++ // Paper start - fix converting txt to json file; moved from constructor ++ } ++ @Override ++ public void loadAndSaveFiles() { ++ // Paper end - fix converting txt to json file + this.loadUserBanList(); + 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 9a3e73a5c206b78dfcf6f41a47b614342e52acc8..9d05e998d6df1069c2de69478a1f9688ac435e67 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -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 ++ // Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save ++ if (this.convertOldUsers()) { ++ this.getProfileCache().save(false); // Paper ++ } ++ this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames ++ // Paper end - fix converting txt to json file + 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 +@@ -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."); + } + +- if (this.convertOldUsers()) { +- this.getProfileCache().save(false); // Paper - Perf: Async GameProfileCache saving +- } + + 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 f023959eee56d8d37cf0a76cb7352c0045cd2ea0..f6861901455fd9e4defb611f4475cfaca653ac30 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -179,6 +179,7 @@ public abstract class PlayerList { + this.maxPlayers = maxPlayers; + this.playerIo = saveHandler; + } ++ abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor + + public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) { + player.isRealPlayer = true; // Paper diff --git a/patches/server/0487-Add-worldborder-events.patch b/patches/server/0487-Add-worldborder-events.patch new file mode 100644 index 0000000000..014dba4c88 --- /dev/null +++ b/patches/server/0487-Add-worldborder-events.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 4 Jan 2021 22:40:34 -0800 +Subject: [PATCH] Add worldborder events + + +diff --git a/src/main/java/net/minecraft/world/level/border/WorldBorder.java b/src/main/java/net/minecraft/world/level/border/WorldBorder.java +index b50090df116697a12f5498d65dd2e5d6d5297fb5..807a097a7b6399f24ede741f94ce98eb67e55add 100644 +--- a/src/main/java/net/minecraft/world/level/border/WorldBorder.java ++++ b/src/main/java/net/minecraft/world/level/border/WorldBorder.java +@@ -148,6 +148,14 @@ public class WorldBorder { + } + + public void setCenter(double x, double z) { ++ // Paper start - Add worldborder events ++ if (this.world != null) { ++ io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), new org.bukkit.Location(world.getWorld(), this.getCenterX(), 0, this.getCenterZ()), new org.bukkit.Location(world.getWorld(), x, 0, z)); ++ if (!event.callEvent()) return; ++ x = event.getNewCenter().getX(); ++ z = event.getNewCenter().getZ(); ++ } ++ // Paper end - Add worldborder events + this.centerX = x; + this.centerZ = z; + this.extent.onCenterChange(); +@@ -174,6 +182,17 @@ public class WorldBorder { + } + + public void setSize(double size) { ++ // Paper start - Add worldborder events ++ if (this.world != null) { ++ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.INSTANT_MOVE, getSize(), size, 0); ++ if (!event.callEvent()) return; ++ if (event.getType() == io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.STARTED_MOVE && event.getDuration() > 0) { // If changed to a timed transition ++ lerpSizeBetween(event.getOldSize(), event.getNewSize(), event.getDuration()); ++ return; ++ } ++ size = event.getNewSize(); ++ } ++ // Paper end - Add worldborder events + this.extent = new WorldBorder.StaticBorderExtent(size); + Iterator iterator = this.getListeners().iterator(); + +@@ -186,6 +205,20 @@ public class WorldBorder { + } + + public void lerpSizeBetween(double fromSize, double toSize, long time) { ++ // Paper start - Add worldborder events ++ if (this.world != null) { ++ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type type; ++ if (fromSize == toSize) { // new size = old size ++ type = io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.INSTANT_MOVE; // Use INSTANT_MOVE because below it creates a Static border if they are equal. ++ } else { ++ type = io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.STARTED_MOVE; ++ } ++ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), type, fromSize, toSize, time); ++ if (!event.callEvent()) return; ++ toSize = event.getNewSize(); ++ time = event.getDuration(); ++ } ++ // Paper end - Add worldborder events + this.extent = (WorldBorder.BorderExtent) (fromSize == toSize ? new WorldBorder.StaticBorderExtent(toSize) : new WorldBorder.MovingBorderExtent(fromSize, toSize, time)); + Iterator iterator = this.getListeners().iterator(); + +@@ -497,6 +530,7 @@ public class WorldBorder { + + @Override + public WorldBorder.BorderExtent update() { ++ if (world != null && this.getLerpRemainingTime() <= 0L) new io.papermc.paper.event.world.border.WorldBorderBoundsChangeFinishEvent(world.getWorld(), world.getWorld().getWorldBorder(), this.from, this.to, this.lerpDuration).callEvent(); // Paper - Add worldborder events + return (WorldBorder.BorderExtent) (this.getLerpRemainingTime() <= 0L ? WorldBorder.this.new StaticBorderExtent(this.to) : this); + } + diff --git a/patches/server/0487-fix-converting-txt-to-json-file.patch b/patches/server/0487-fix-converting-txt-to-json-file.patch deleted file mode 100644 index b71e73914b..0000000000 --- a/patches/server/0487-fix-converting-txt-to-json-file.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 4 Jan 2021 19:49:15 -0800 -Subject: [PATCH] fix converting txt to json file - - -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java -index 929f59bce01c8e6ed4b0b551744d42e131b8fc80..22c4f8dea99f92a1eb3da2baf0a15bf9d2ca0462 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java -@@ -18,6 +18,11 @@ public class DedicatedPlayerList extends PlayerList { - this.setViewDistance(dedicatedServerProperties.viewDistance); - this.setSimulationDistance(dedicatedServerProperties.simulationDistance); - super.setUsingWhiteList(dedicatedServerProperties.whiteList.get()); -+ // Paper start - fix converting txt to json file; moved from constructor -+ } -+ @Override -+ public void loadAndSaveFiles() { -+ // Paper end - fix converting txt to json file - this.loadUserBanList(); - 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 9a3e73a5c206b78dfcf6f41a47b614342e52acc8..9d05e998d6df1069c2de69478a1f9688ac435e67 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -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 -+ // Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save -+ if (this.convertOldUsers()) { -+ this.getProfileCache().save(false); // Paper -+ } -+ this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames -+ // Paper end - fix converting txt to json file - 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 -@@ -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."); - } - -- if (this.convertOldUsers()) { -- this.getProfileCache().save(false); // Paper - Perf: Async GameProfileCache saving -- } - - 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 f023959eee56d8d37cf0a76cb7352c0045cd2ea0..f6861901455fd9e4defb611f4475cfaca653ac30 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -179,6 +179,7 @@ public abstract class PlayerList { - this.maxPlayers = maxPlayers; - this.playerIo = saveHandler; - } -+ abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor - - public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) { - player.isRealPlayer = true; // Paper diff --git a/patches/server/0488-Add-PlayerNameEntityEvent.patch b/patches/server/0488-Add-PlayerNameEntityEvent.patch new file mode 100644 index 0000000000..8d982f76db --- /dev/null +++ b/patches/server/0488-Add-PlayerNameEntityEvent.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 5 Jul 2020 00:33:54 -0700 +Subject: [PATCH] Add PlayerNameEntityEvent + + +diff --git a/src/main/java/net/minecraft/world/item/NameTagItem.java b/src/main/java/net/minecraft/world/item/NameTagItem.java +index 244663ff31bdb29bbff8b3ffd9fe99279b173296..df9cdcb9544a171a5a07c65ba0150933fb70d5fc 100644 +--- a/src/main/java/net/minecraft/world/item/NameTagItem.java ++++ b/src/main/java/net/minecraft/world/item/NameTagItem.java +@@ -18,8 +18,13 @@ public class NameTagItem extends Item { + Component component = stack.get(DataComponents.CUSTOM_NAME); + if (component != null && entity.getType().canSerialize() && entity.canBeNameTagged()) { + if (!user.level().isClientSide && entity.isAlive()) { +- entity.setCustomName(component); +- if (entity instanceof Mob mob) { ++ // Paper start - Add PlayerNameEntityEvent ++ io.papermc.paper.event.player.PlayerNameEntityEvent event = new io.papermc.paper.event.player.PlayerNameEntityEvent(((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity(), entity.getBukkitLivingEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(stack.getHoverName()), true); ++ if (!event.callEvent()) return InteractionResult.PASS; ++ LivingEntity newEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getEntity()).getHandle(); ++ newEntity.setCustomName(event.getName() != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(event.getName()) : null); ++ if (event.isPersistent() && newEntity instanceof Mob mob) { ++ // Paper end - Add PlayerNameEntityEvent + mob.setPersistenceRequired(); + } + diff --git a/patches/server/0488-Add-worldborder-events.patch b/patches/server/0488-Add-worldborder-events.patch deleted file mode 100644 index 014dba4c88..0000000000 --- a/patches/server/0488-Add-worldborder-events.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 4 Jan 2021 22:40:34 -0800 -Subject: [PATCH] Add worldborder events - - -diff --git a/src/main/java/net/minecraft/world/level/border/WorldBorder.java b/src/main/java/net/minecraft/world/level/border/WorldBorder.java -index b50090df116697a12f5498d65dd2e5d6d5297fb5..807a097a7b6399f24ede741f94ce98eb67e55add 100644 ---- a/src/main/java/net/minecraft/world/level/border/WorldBorder.java -+++ b/src/main/java/net/minecraft/world/level/border/WorldBorder.java -@@ -148,6 +148,14 @@ public class WorldBorder { - } - - public void setCenter(double x, double z) { -+ // Paper start - Add worldborder events -+ if (this.world != null) { -+ io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), new org.bukkit.Location(world.getWorld(), this.getCenterX(), 0, this.getCenterZ()), new org.bukkit.Location(world.getWorld(), x, 0, z)); -+ if (!event.callEvent()) return; -+ x = event.getNewCenter().getX(); -+ z = event.getNewCenter().getZ(); -+ } -+ // Paper end - Add worldborder events - this.centerX = x; - this.centerZ = z; - this.extent.onCenterChange(); -@@ -174,6 +182,17 @@ public class WorldBorder { - } - - public void setSize(double size) { -+ // Paper start - Add worldborder events -+ if (this.world != null) { -+ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.INSTANT_MOVE, getSize(), size, 0); -+ if (!event.callEvent()) return; -+ if (event.getType() == io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.STARTED_MOVE && event.getDuration() > 0) { // If changed to a timed transition -+ lerpSizeBetween(event.getOldSize(), event.getNewSize(), event.getDuration()); -+ return; -+ } -+ size = event.getNewSize(); -+ } -+ // Paper end - Add worldborder events - this.extent = new WorldBorder.StaticBorderExtent(size); - Iterator iterator = this.getListeners().iterator(); - -@@ -186,6 +205,20 @@ public class WorldBorder { - } - - public void lerpSizeBetween(double fromSize, double toSize, long time) { -+ // Paper start - Add worldborder events -+ if (this.world != null) { -+ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type type; -+ if (fromSize == toSize) { // new size = old size -+ type = io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.INSTANT_MOVE; // Use INSTANT_MOVE because below it creates a Static border if they are equal. -+ } else { -+ type = io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.STARTED_MOVE; -+ } -+ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), type, fromSize, toSize, time); -+ if (!event.callEvent()) return; -+ toSize = event.getNewSize(); -+ time = event.getDuration(); -+ } -+ // Paper end - Add worldborder events - this.extent = (WorldBorder.BorderExtent) (fromSize == toSize ? new WorldBorder.StaticBorderExtent(toSize) : new WorldBorder.MovingBorderExtent(fromSize, toSize, time)); - Iterator iterator = this.getListeners().iterator(); - -@@ -497,6 +530,7 @@ public class WorldBorder { - - @Override - public WorldBorder.BorderExtent update() { -+ if (world != null && this.getLerpRemainingTime() <= 0L) new io.papermc.paper.event.world.border.WorldBorderBoundsChangeFinishEvent(world.getWorld(), world.getWorld().getWorldBorder(), this.from, this.to, this.lerpDuration).callEvent(); // Paper - Add worldborder events - return (WorldBorder.BorderExtent) (this.getLerpRemainingTime() <= 0L ? WorldBorder.this.new StaticBorderExtent(this.to) : this); - } - diff --git a/patches/server/0489-Add-PlayerNameEntityEvent.patch b/patches/server/0489-Add-PlayerNameEntityEvent.patch deleted file mode 100644 index 8d982f76db..0000000000 --- a/patches/server/0489-Add-PlayerNameEntityEvent.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 5 Jul 2020 00:33:54 -0700 -Subject: [PATCH] Add PlayerNameEntityEvent - - -diff --git a/src/main/java/net/minecraft/world/item/NameTagItem.java b/src/main/java/net/minecraft/world/item/NameTagItem.java -index 244663ff31bdb29bbff8b3ffd9fe99279b173296..df9cdcb9544a171a5a07c65ba0150933fb70d5fc 100644 ---- a/src/main/java/net/minecraft/world/item/NameTagItem.java -+++ b/src/main/java/net/minecraft/world/item/NameTagItem.java -@@ -18,8 +18,13 @@ public class NameTagItem extends Item { - Component component = stack.get(DataComponents.CUSTOM_NAME); - if (component != null && entity.getType().canSerialize() && entity.canBeNameTagged()) { - if (!user.level().isClientSide && entity.isAlive()) { -- entity.setCustomName(component); -- if (entity instanceof Mob mob) { -+ // Paper start - Add PlayerNameEntityEvent -+ io.papermc.paper.event.player.PlayerNameEntityEvent event = new io.papermc.paper.event.player.PlayerNameEntityEvent(((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity(), entity.getBukkitLivingEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(stack.getHoverName()), true); -+ if (!event.callEvent()) return InteractionResult.PASS; -+ LivingEntity newEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getEntity()).getHandle(); -+ newEntity.setCustomName(event.getName() != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(event.getName()) : null); -+ if (event.isPersistent() && newEntity instanceof Mob mob) { -+ // Paper end - Add PlayerNameEntityEvent - mob.setPersistenceRequired(); - } - diff --git a/patches/server/0489-Add-recipe-to-cook-events.patch b/patches/server/0489-Add-recipe-to-cook-events.patch new file mode 100644 index 0000000000..416e598dc6 --- /dev/null +++ b/patches/server/0489-Add-recipe-to-cook-events.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> +Date: Wed, 6 Jan 2021 12:04:03 -0800 +Subject: [PATCH] Add recipe to cook events + + +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 b2c0de191fdc84d4a007373309a5df81cacd5466..4acf487f9a5f3fa828ee76f9708d6a2ae28707e1 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 +@@ -327,7 +327,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit + CraftItemStack source = CraftItemStack.asCraftMirror(itemstack); + org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1); + +- FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(CraftBlock.at(world, blockposition), source, result); ++ FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(CraftBlock.at(world, blockposition), source, result, (org.bukkit.inventory.CookingRecipe) recipeholder.toBukkitRecipe()); // Paper - Add recipe to cook events + world.getCraftServer().getPluginManager().callEvent(furnaceSmeltEvent); + + if (furnaceSmeltEvent.isCancelled()) { +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 30035d534e144bf31f94073c57b0195be7e62772..7fa1aea7942a1bc4d9779a9f8ab020ccd5566923 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 +@@ -66,7 +66,10 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { + + if (blockEntity.cookingProgress[i] >= blockEntity.cookingTime[i]) { + SingleRecipeInput singlerecipeinput = new SingleRecipeInput(itemstack); +- ItemStack itemstack1 = (ItemStack) recipeMatchGetter.getRecipeFor(singlerecipeinput, world).map((recipeholder) -> { ++ // Paper start - add recipe to cook events ++ final Optional> recipeHolderOptional = recipeMatchGetter.getRecipeFor(singlerecipeinput, world); ++ ItemStack itemstack1 = (ItemStack) recipeHolderOptional.map((recipeholder) -> { ++ // Paper end - add recipe to cook events + return ((CampfireCookingRecipe) recipeholder.value()).assemble(singlerecipeinput, world.registryAccess()); + }).orElse(itemstack); + +@@ -75,7 +78,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { + CraftItemStack source = CraftItemStack.asCraftMirror(itemstack); + org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1); + +- BlockCookEvent blockCookEvent = new BlockCookEvent(CraftBlock.at(world, pos), source, result); ++ BlockCookEvent blockCookEvent = new BlockCookEvent(CraftBlock.at(world, pos), source, result, (org.bukkit.inventory.CookingRecipe) recipeHolderOptional.map(RecipeHolder::toBukkitRecipe).orElse(null)); // Paper - Add recipe to cook events + world.getCraftServer().getPluginManager().callEvent(blockCookEvent); + + if (blockCookEvent.isCancelled()) { diff --git a/patches/server/0490-Add-Block-isValidTool.patch b/patches/server/0490-Add-Block-isValidTool.patch new file mode 100644 index 0000000000..e0c42e8e37 --- /dev/null +++ b/patches/server/0490-Add-Block-isValidTool.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 6 Jul 2020 12:44:31 -0700 +Subject: [PATCH] Add Block#isValidTool + + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 1595e877b02b447b36f5c316ae70d4023b78a862..54fb380a6896731a18c0100722d12099e590cbc9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -693,5 +693,9 @@ public class CraftBlock implements Block { + public String translationKey() { + return this.getNMS().getBlock().getDescriptionId(); + } ++ ++ public boolean isValidTool(ItemStack itemStack) { ++ return getDrops(itemStack).size() != 0; ++ } + // Paper end + } diff --git a/patches/server/0490-Add-recipe-to-cook-events.patch b/patches/server/0490-Add-recipe-to-cook-events.patch deleted file mode 100644 index 416e598dc6..0000000000 --- a/patches/server/0490-Add-recipe-to-cook-events.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com> -Date: Wed, 6 Jan 2021 12:04:03 -0800 -Subject: [PATCH] Add recipe to cook events - - -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 b2c0de191fdc84d4a007373309a5df81cacd5466..4acf487f9a5f3fa828ee76f9708d6a2ae28707e1 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 -@@ -327,7 +327,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - CraftItemStack source = CraftItemStack.asCraftMirror(itemstack); - org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1); - -- FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(CraftBlock.at(world, blockposition), source, result); -+ FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(CraftBlock.at(world, blockposition), source, result, (org.bukkit.inventory.CookingRecipe) recipeholder.toBukkitRecipe()); // Paper - Add recipe to cook events - world.getCraftServer().getPluginManager().callEvent(furnaceSmeltEvent); - - if (furnaceSmeltEvent.isCancelled()) { -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 30035d534e144bf31f94073c57b0195be7e62772..7fa1aea7942a1bc4d9779a9f8ab020ccd5566923 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 -@@ -66,7 +66,10 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { - - if (blockEntity.cookingProgress[i] >= blockEntity.cookingTime[i]) { - SingleRecipeInput singlerecipeinput = new SingleRecipeInput(itemstack); -- ItemStack itemstack1 = (ItemStack) recipeMatchGetter.getRecipeFor(singlerecipeinput, world).map((recipeholder) -> { -+ // Paper start - add recipe to cook events -+ final Optional> recipeHolderOptional = recipeMatchGetter.getRecipeFor(singlerecipeinput, world); -+ ItemStack itemstack1 = (ItemStack) recipeHolderOptional.map((recipeholder) -> { -+ // Paper end - add recipe to cook events - return ((CampfireCookingRecipe) recipeholder.value()).assemble(singlerecipeinput, world.registryAccess()); - }).orElse(itemstack); - -@@ -75,7 +78,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { - CraftItemStack source = CraftItemStack.asCraftMirror(itemstack); - org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1); - -- BlockCookEvent blockCookEvent = new BlockCookEvent(CraftBlock.at(world, pos), source, result); -+ BlockCookEvent blockCookEvent = new BlockCookEvent(CraftBlock.at(world, pos), source, result, (org.bukkit.inventory.CookingRecipe) recipeHolderOptional.map(RecipeHolder::toBukkitRecipe).orElse(null)); // Paper - Add recipe to cook events - world.getCraftServer().getPluginManager().callEvent(blockCookEvent); - - if (blockCookEvent.isCancelled()) { diff --git a/patches/server/0491-Add-Block-isValidTool.patch b/patches/server/0491-Add-Block-isValidTool.patch deleted file mode 100644 index e0c42e8e37..0000000000 --- a/patches/server/0491-Add-Block-isValidTool.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 6 Jul 2020 12:44:31 -0700 -Subject: [PATCH] Add Block#isValidTool - - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 1595e877b02b447b36f5c316ae70d4023b78a862..54fb380a6896731a18c0100722d12099e590cbc9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -693,5 +693,9 @@ public class CraftBlock implements Block { - public String translationKey() { - return this.getNMS().getBlock().getDescriptionId(); - } -+ -+ public boolean isValidTool(ItemStack itemStack) { -+ return getDrops(itemStack).size() != 0; -+ } - // Paper end - } diff --git a/patches/server/0491-Allow-using-signs-inside-spawn-protection.patch b/patches/server/0491-Allow-using-signs-inside-spawn-protection.patch new file mode 100644 index 0000000000..e9bc959bc0 --- /dev/null +++ b/patches/server/0491-Allow-using-signs-inside-spawn-protection.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Anton Lindroth +Date: Wed, 15 Apr 2020 01:54:02 +0200 +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 76b6c3fca13590f057dc4767d27fef4192974147..26900978386bc97be6f224e9428fae051be6fc22 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1827,7 +1827,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + int i = this.player.level().getMaxY(); + + if (blockposition.getY() <= i) { +- if (this.awaitingPositionFromClient == null && worldserver.mayInteract(this.player, blockposition)) { ++ if (this.awaitingPositionFromClient == null && (worldserver.mayInteract(this.player, blockposition) || (worldserver.paperConfig().spawn.allowUsingSignsInsideSpawnProtection && worldserver.getBlockState(blockposition).getBlock() instanceof net.minecraft.world.level.block.SignBlock))) { // Paper - Allow using signs inside spawn protection + this.player.stopUsingItem(); // CraftBukkit - SPIGOT-4706 + InteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock); + diff --git a/patches/server/0492-Allow-using-signs-inside-spawn-protection.patch b/patches/server/0492-Allow-using-signs-inside-spawn-protection.patch deleted file mode 100644 index e9bc959bc0..0000000000 --- a/patches/server/0492-Allow-using-signs-inside-spawn-protection.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Anton Lindroth -Date: Wed, 15 Apr 2020 01:54:02 +0200 -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 76b6c3fca13590f057dc4767d27fef4192974147..26900978386bc97be6f224e9428fae051be6fc22 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1827,7 +1827,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - int i = this.player.level().getMaxY(); - - if (blockposition.getY() <= i) { -- if (this.awaitingPositionFromClient == null && worldserver.mayInteract(this.player, blockposition)) { -+ if (this.awaitingPositionFromClient == null && (worldserver.mayInteract(this.player, blockposition) || (worldserver.paperConfig().spawn.allowUsingSignsInsideSpawnProtection && worldserver.getBlockState(blockposition).getBlock() instanceof net.minecraft.world.level.block.SignBlock))) { // Paper - Allow using signs inside spawn protection - this.player.stopUsingItem(); // CraftBukkit - SPIGOT-4706 - InteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock); - diff --git a/patches/server/0492-Expand-world-key-API.patch b/patches/server/0492-Expand-world-key-API.patch new file mode 100644 index 0000000000..7e7d90c838 --- /dev/null +++ b/patches/server/0492-Expand-world-key-API.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 6 Jan 2021 00:34:04 -0800 +Subject: [PATCH] Expand world key API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +index 15da29058f80a2d7cf2be26c48421c1746815a10..a070b2a83edaa702b13bc6d3026914126c211576 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +@@ -521,5 +521,10 @@ public abstract class CraftRegionAccessor implements RegionAccessor { + public io.papermc.paper.world.MoonPhase getMoonPhase() { + return io.papermc.paper.world.MoonPhase.getPhase(this.getHandle().dayTime() / 24000L); + } ++ ++ @Override ++ public org.bukkit.NamespacedKey getKey() { ++ return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.getHandle().getLevel().dimension().location()); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 5ae8f646083fb580ac8d28fcbfe8ed2208b45d09..3cfacacd1d8fd17ec4b54936afd8124823b1a00b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1185,9 +1185,15 @@ public final class CraftServer implements Server { + File folder = new File(this.getWorldContainer(), name); + World world = this.getWorld(name); + +- if (world != null) { +- return world; ++ // Paper start ++ World worldByKey = this.getWorld(creator.key()); ++ if (world != null || worldByKey != null) { ++ if (world == worldByKey) { ++ return world; ++ } ++ throw new IllegalArgumentException("Cannot create a world with key " + creator.key() + " and name " + name + " one (or both) already match a world that exists"); + } ++ // Paper end + + if (folder.exists()) { + Preconditions.checkArgument(folder.isDirectory(), "File (%s) exists and isn't a folder", name); +@@ -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 { +- worldKey = ResourceKey.create(Registries.DIMENSION, ResourceLocation.withDefaultNamespace(name.toLowerCase(Locale.ROOT))); ++ worldKey = ResourceKey.create(Registries.DIMENSION, ResourceLocation.fromNamespaceAndPath(creator.key().namespace(), creator.key().value())); + } + + // If set to not keep spawn in memory (changed from default) then adjust rule accordingly +@@ -1409,6 +1415,15 @@ public final class CraftServer implements Server { + return null; + } + ++ // Paper start ++ @Override ++ public World getWorld(net.kyori.adventure.key.Key worldKey) { ++ ServerLevel worldServer = console.getLevel(ResourceKey.create(net.minecraft.core.registries.Registries.DIMENSION, io.papermc.paper.adventure.PaperAdventure.asVanilla(worldKey))); ++ if (worldServer == null) return null; ++ return worldServer.getWorld(); ++ } ++ // Paper end ++ + public void addWorld(World world) { + // 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 5f0fd1d4fe419435ac7293106c0ebb5382d64074..8d9380b50424546bcebdfa868635f94c8efa5899 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -538,6 +538,11 @@ public final class CraftMagicNumbers implements UnsafeValues { + public int nextEntityId() { + return net.minecraft.world.entity.Entity.nextEntityId(); + } ++ ++ @Override ++ public String getMainLevelName() { ++ return ((net.minecraft.server.dedicated.DedicatedServer) net.minecraft.server.MinecraftServer.getServer()).getProperties().levelName; ++ } + // Paper end + + /** diff --git a/patches/server/0493-Add-fast-alternative-constructor-for-Rotations.patch b/patches/server/0493-Add-fast-alternative-constructor-for-Rotations.patch new file mode 100644 index 0000000000..e28775fc9a --- /dev/null +++ b/patches/server/0493-Add-fast-alternative-constructor-for-Rotations.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Irmo van den Berge +Date: Wed, 10 Mar 2021 21:26:31 +0100 +Subject: [PATCH] Add fast alternative constructor for Rotations + + +diff --git a/src/main/java/net/minecraft/core/Rotations.java b/src/main/java/net/minecraft/core/Rotations.java +index e6c97efb3aa89646149d11bb0ae4420b3977d214..27007280dba9e6d19a50dc2a4b160e96b20c67f7 100644 +--- a/src/main/java/net/minecraft/core/Rotations.java ++++ b/src/main/java/net/minecraft/core/Rotations.java +@@ -34,6 +34,18 @@ public class Rotations { + this(serialized.getFloat(0), serialized.getFloat(1), serialized.getFloat(2)); + } + ++ // Paper start - faster alternative constructor ++ private Rotations(float x, float y, float z, Void dummy_var) { ++ this.x = x; ++ this.y = y; ++ this.z = z; ++ } ++ ++ public static Rotations createWithoutValidityChecks(float x, float y, float z) { ++ return new Rotations(x, y, z, null); ++ } ++ // Paper end - faster alternative constructor ++ + public ListTag save() { + ListTag listTag = new ListTag(); + listTag.add(FloatTag.valueOf(this.x)); diff --git a/patches/server/0493-Expand-world-key-API.patch b/patches/server/0493-Expand-world-key-API.patch deleted file mode 100644 index 7e7d90c838..0000000000 --- a/patches/server/0493-Expand-world-key-API.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 6 Jan 2021 00:34:04 -0800 -Subject: [PATCH] Expand world key API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -index 15da29058f80a2d7cf2be26c48421c1746815a10..a070b2a83edaa702b13bc6d3026914126c211576 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -@@ -521,5 +521,10 @@ public abstract class CraftRegionAccessor implements RegionAccessor { - public io.papermc.paper.world.MoonPhase getMoonPhase() { - return io.papermc.paper.world.MoonPhase.getPhase(this.getHandle().dayTime() / 24000L); - } -+ -+ @Override -+ public org.bukkit.NamespacedKey getKey() { -+ return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.getHandle().getLevel().dimension().location()); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 5ae8f646083fb580ac8d28fcbfe8ed2208b45d09..3cfacacd1d8fd17ec4b54936afd8124823b1a00b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1185,9 +1185,15 @@ public final class CraftServer implements Server { - File folder = new File(this.getWorldContainer(), name); - World world = this.getWorld(name); - -- if (world != null) { -- return world; -+ // Paper start -+ World worldByKey = this.getWorld(creator.key()); -+ if (world != null || worldByKey != null) { -+ if (world == worldByKey) { -+ return world; -+ } -+ throw new IllegalArgumentException("Cannot create a world with key " + creator.key() + " and name " + name + " one (or both) already match a world that exists"); - } -+ // Paper end - - if (folder.exists()) { - Preconditions.checkArgument(folder.isDirectory(), "File (%s) exists and isn't a folder", name); -@@ -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 { -- worldKey = ResourceKey.create(Registries.DIMENSION, ResourceLocation.withDefaultNamespace(name.toLowerCase(Locale.ROOT))); -+ worldKey = ResourceKey.create(Registries.DIMENSION, ResourceLocation.fromNamespaceAndPath(creator.key().namespace(), creator.key().value())); - } - - // If set to not keep spawn in memory (changed from default) then adjust rule accordingly -@@ -1409,6 +1415,15 @@ public final class CraftServer implements Server { - return null; - } - -+ // Paper start -+ @Override -+ public World getWorld(net.kyori.adventure.key.Key worldKey) { -+ ServerLevel worldServer = console.getLevel(ResourceKey.create(net.minecraft.core.registries.Registries.DIMENSION, io.papermc.paper.adventure.PaperAdventure.asVanilla(worldKey))); -+ if (worldServer == null) return null; -+ return worldServer.getWorld(); -+ } -+ // Paper end -+ - public void addWorld(World world) { - // 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 5f0fd1d4fe419435ac7293106c0ebb5382d64074..8d9380b50424546bcebdfa868635f94c8efa5899 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -538,6 +538,11 @@ public final class CraftMagicNumbers implements UnsafeValues { - public int nextEntityId() { - return net.minecraft.world.entity.Entity.nextEntityId(); - } -+ -+ @Override -+ public String getMainLevelName() { -+ return ((net.minecraft.server.dedicated.DedicatedServer) net.minecraft.server.MinecraftServer.getServer()).getProperties().levelName; -+ } - // Paper end - - /** diff --git a/patches/server/0494-Add-fast-alternative-constructor-for-Rotations.patch b/patches/server/0494-Add-fast-alternative-constructor-for-Rotations.patch deleted file mode 100644 index e28775fc9a..0000000000 --- a/patches/server/0494-Add-fast-alternative-constructor-for-Rotations.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Irmo van den Berge -Date: Wed, 10 Mar 2021 21:26:31 +0100 -Subject: [PATCH] Add fast alternative constructor for Rotations - - -diff --git a/src/main/java/net/minecraft/core/Rotations.java b/src/main/java/net/minecraft/core/Rotations.java -index e6c97efb3aa89646149d11bb0ae4420b3977d214..27007280dba9e6d19a50dc2a4b160e96b20c67f7 100644 ---- a/src/main/java/net/minecraft/core/Rotations.java -+++ b/src/main/java/net/minecraft/core/Rotations.java -@@ -34,6 +34,18 @@ public class Rotations { - this(serialized.getFloat(0), serialized.getFloat(1), serialized.getFloat(2)); - } - -+ // Paper start - faster alternative constructor -+ private Rotations(float x, float y, float z, Void dummy_var) { -+ this.x = x; -+ this.y = y; -+ this.z = z; -+ } -+ -+ public static Rotations createWithoutValidityChecks(float x, float y, float z) { -+ return new Rotations(x, y, z, null); -+ } -+ // Paper end - faster alternative constructor -+ - public ListTag save() { - ListTag listTag = new ListTag(); - listTag.add(FloatTag.valueOf(this.x)); diff --git a/patches/server/0494-Drop-carried-item-when-player-has-disconnected.patch b/patches/server/0494-Drop-carried-item-when-player-has-disconnected.patch new file mode 100644 index 0000000000..588c687302 --- /dev/null +++ b/patches/server/0494-Drop-carried-item-when-player-has-disconnected.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dmitry Sidorov +Date: Thu, 4 Feb 2021 20:32:01 +0300 +Subject: [PATCH] Drop carried item when player has disconnected + +Fixes disappearance of held items, when a player gets disconnected and PlayerDropItemEvent is cancelled. +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 f6861901455fd9e4defb611f4475cfaca653ac30..ee6a3e8a8827468d787f5aa116d9876ae7654352 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -537,6 +537,14 @@ public abstract class PlayerList { + } + // Paper end - Configurable player collision + ++ // Paper - Drop carried item when player has disconnected ++ if (!entityplayer.containerMenu.getCarried().isEmpty()) { ++ net.minecraft.world.item.ItemStack carried = entityplayer.containerMenu.getCarried(); ++ entityplayer.containerMenu.setCarried(net.minecraft.world.item.ItemStack.EMPTY); ++ entityplayer.drop(carried, false); ++ } ++ // Paper end - Drop carried item when player has disconnected ++ + this.save(entityplayer); + if (entityplayer.isPassenger()) { + Entity entity = entityplayer.getRootVehicle(); diff --git a/patches/server/0495-Drop-carried-item-when-player-has-disconnected.patch b/patches/server/0495-Drop-carried-item-when-player-has-disconnected.patch deleted file mode 100644 index 588c687302..0000000000 --- a/patches/server/0495-Drop-carried-item-when-player-has-disconnected.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Dmitry Sidorov -Date: Thu, 4 Feb 2021 20:32:01 +0300 -Subject: [PATCH] Drop carried item when player has disconnected - -Fixes disappearance of held items, when a player gets disconnected and PlayerDropItemEvent is cancelled. -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 f6861901455fd9e4defb611f4475cfaca653ac30..ee6a3e8a8827468d787f5aa116d9876ae7654352 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -537,6 +537,14 @@ public abstract class PlayerList { - } - // Paper end - Configurable player collision - -+ // Paper - Drop carried item when player has disconnected -+ if (!entityplayer.containerMenu.getCarried().isEmpty()) { -+ net.minecraft.world.item.ItemStack carried = entityplayer.containerMenu.getCarried(); -+ entityplayer.containerMenu.setCarried(net.minecraft.world.item.ItemStack.EMPTY); -+ entityplayer.drop(carried, false); -+ } -+ // Paper end - Drop carried item when player has disconnected -+ - this.save(entityplayer); - if (entityplayer.isPassenger()) { - Entity entity = entityplayer.getRootVehicle(); diff --git a/patches/server/0495-forced-whitelist-use-configurable-kick-message.patch b/patches/server/0495-forced-whitelist-use-configurable-kick-message.patch new file mode 100644 index 0000000000..f9aab54d8f --- /dev/null +++ b/patches/server/0495-forced-whitelist-use-configurable-kick-message.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Trigary +Date: Sat, 27 Mar 2021 09:24:23 +0100 +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 b28a2756429270414f8ef89539f91ce0595d13c6..0ab92fb362729108beca6bc0230fb6fb06ca6280 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -2325,7 +2325,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Mon, 5 Apr 2021 18:35:15 -0700 +Subject: [PATCH] Don't ignore result of PlayerEditBookEvent + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 26900978386bc97be6f224e9428fae051be6fc22..7a38ddcfb2ee373e9464f486bf968210ef10dd1a 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1219,7 +1219,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + List> list1 = pages.stream().map(this::filterableFromOutgoing).toList(); + + itemstack.set(DataComponents.WRITABLE_BOOK_CONTENT, new WritableBookContent(list1)); +- CraftEventFactory.handleEditBookEvent(this.player, slotId, handItem, itemstack); // CraftBukkit ++ this.player.getInventory().setItem(slotId, CraftEventFactory.handleEditBookEvent(this.player, slotId, handItem, itemstack)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent) + } + } + diff --git a/patches/server/0496-forced-whitelist-use-configurable-kick-message.patch b/patches/server/0496-forced-whitelist-use-configurable-kick-message.patch deleted file mode 100644 index f9aab54d8f..0000000000 --- a/patches/server/0496-forced-whitelist-use-configurable-kick-message.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trigary -Date: Sat, 27 Mar 2021 09:24:23 +0100 -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 b28a2756429270414f8ef89539f91ce0595d13c6..0ab92fb362729108beca6bc0230fb6fb06ca6280 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2325,7 +2325,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Mon, 5 Apr 2021 18:35:15 -0700 -Subject: [PATCH] Don't ignore result of PlayerEditBookEvent - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 26900978386bc97be6f224e9428fae051be6fc22..7a38ddcfb2ee373e9464f486bf968210ef10dd1a 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1219,7 +1219,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - List> list1 = pages.stream().map(this::filterableFromOutgoing).toList(); - - itemstack.set(DataComponents.WRITABLE_BOOK_CONTENT, new WritableBookContent(list1)); -- CraftEventFactory.handleEditBookEvent(this.player, slotId, handItem, itemstack); // CraftBukkit -+ this.player.getInventory().setItem(slotId, CraftEventFactory.handleEditBookEvent(this.player, slotId, handItem, itemstack)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent) - } - } - diff --git a/patches/server/0497-Expose-protocol-version.patch b/patches/server/0497-Expose-protocol-version.patch new file mode 100644 index 0000000000..cd6a7ab2b0 --- /dev/null +++ b/patches/server/0497-Expose-protocol-version.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Fri, 26 Mar 2021 11:23:17 +0100 +Subject: [PATCH] Expose protocol version + + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 8d9380b50424546bcebdfa868635f94c8efa5899..30f2ddb66385718304b4b0302f7efcafd54bc42a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -543,6 +543,11 @@ public final class CraftMagicNumbers implements UnsafeValues { + public String getMainLevelName() { + return ((net.minecraft.server.dedicated.DedicatedServer) net.minecraft.server.MinecraftServer.getServer()).getProperties().levelName; + } ++ ++ @Override ++ public int getProtocolVersion() { ++ return net.minecraft.SharedConstants.getCurrentVersion().getProtocolVersion(); ++ } + // Paper end + + /** diff --git a/patches/server/0498-Enhance-console-tab-completions-for-brigadier-comman.patch b/patches/server/0498-Enhance-console-tab-completions-for-brigadier-comman.patch new file mode 100644 index 0000000000..3d1a0fb945 --- /dev/null +++ b/patches/server/0498-Enhance-console-tab-completions-for-brigadier-comman.patch @@ -0,0 +1,445 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Tue, 30 Mar 2021 16:06:08 -0700 +Subject: [PATCH] Enhance console tab completions for brigadier commands + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java +index a4070b59e261f0f1ac4beec47b11492f4724bf27..6ee39b534b8d992655bc0cef3c299d12cbae0034 100644 +--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java ++++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java +@@ -1,5 +1,8 @@ + package com.destroystokyo.paper.console; + ++import io.papermc.paper.configuration.GlobalConfiguration; ++import io.papermc.paper.console.BrigadierCompletionMatcher; ++import io.papermc.paper.console.BrigadierConsoleParser; + import net.minecraft.server.dedicated.DedicatedServer; + import net.minecrell.terminalconsole.SimpleTerminalConsole; + import org.bukkit.craftbukkit.command.ConsoleCommandCompleter; +@@ -16,11 +19,20 @@ public final class PaperConsole extends SimpleTerminalConsole { + + @Override + protected LineReader buildReader(LineReaderBuilder builder) { +- return super.buildReader(builder ++ builder + .appName("Paper") + .variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history")) + .completer(new ConsoleCommandCompleter(this.server)) +- ); ++ .option(LineReader.Option.COMPLETE_IN_WORD, true); ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierHighlighting) { ++ builder.highlighter(new io.papermc.paper.console.BrigadierCommandHighlighter(this.server)); ++ } ++ if (GlobalConfiguration.get().console.enableBrigadierCompletions) { ++ System.setProperty("org.jline.reader.support.parsedline", "true"); // to hide a warning message about the parser not supporting ++ builder.parser(new BrigadierConsoleParser(this.server)); ++ builder.completionMatcher(new BrigadierCompletionMatcher()); ++ } ++ return super.buildReader(builder); + } + + @Override +diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bf7b9518c05ff8a6d4b7d7cd36187ca22257e3dc +--- /dev/null ++++ b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java +@@ -0,0 +1,119 @@ ++package io.papermc.paper.console; ++ ++import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent; ++import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion; ++import com.google.common.base.Suppliers; ++import com.mojang.brigadier.CommandDispatcher; ++import com.mojang.brigadier.ParseResults; ++import com.mojang.brigadier.StringReader; ++import com.mojang.brigadier.suggestion.Suggestion; ++import io.papermc.paper.adventure.PaperAdventure; ++import java.util.ArrayList; ++import java.util.Collections; ++import java.util.List; ++import java.util.function.Supplier; ++import net.kyori.adventure.text.Component; ++import net.minecraft.commands.CommandSourceStack; ++import net.minecraft.network.chat.ComponentUtils; ++import net.minecraft.server.dedicated.DedicatedServer; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.jline.reader.Candidate; ++import org.jline.reader.LineReader; ++import org.jline.reader.ParsedLine; ++ ++import static com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion.completion; ++ ++public final class BrigadierCommandCompleter { ++ private final Supplier commandSourceStack; ++ private final DedicatedServer server; ++ ++ public BrigadierCommandCompleter(final @NonNull DedicatedServer server) { ++ this.server = server; ++ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack); ++ } ++ ++ public void complete(final @NonNull LineReader reader, final @NonNull ParsedLine line, final @NonNull List candidates, final @NonNull List existing) { ++ //noinspection ConstantConditions ++ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet ++ return; ++ } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierCompletions) { ++ this.addCandidates(candidates, Collections.emptyList(), existing, new ParseContext(line.line(), 0)); ++ return; ++ } ++ final CommandDispatcher dispatcher = this.server.getCommands().getDispatcher(); ++ final ParseResults results = dispatcher.parse(new StringReader(line.line()), this.commandSourceStack.get()); ++ this.addCandidates( ++ candidates, ++ dispatcher.getCompletionSuggestions(results, line.cursor()).join().getList(), ++ existing, ++ new ParseContext(line.line(), results.getContext().findSuggestionContext(line.cursor()).startPos) ++ ); ++ } ++ ++ private void addCandidates( ++ final @NonNull List candidates, ++ final @NonNull List brigSuggestions, ++ final @NonNull List existing, ++ final @NonNull ParseContext context ++ ) { ++ brigSuggestions.forEach(it -> { ++ if (it.getText().isEmpty()) return; ++ candidates.add(toCandidate(it, context)); ++ }); ++ for (final AsyncTabCompleteEvent.Completion completion : existing) { ++ if (completion.suggestion().isEmpty() || brigSuggestions.stream().anyMatch(it -> it.getText().equals(completion.suggestion()))) { ++ continue; ++ } ++ candidates.add(toCandidate(completion)); ++ } ++ } ++ ++ private static Candidate toCandidate(final Suggestion suggestion, final @NonNull ParseContext context) { ++ Component tooltip = null; ++ if (suggestion.getTooltip() != null) { ++ tooltip = PaperAdventure.asAdventure(ComponentUtils.fromMessage(suggestion.getTooltip())); ++ } ++ return toCandidate(context.line.substring(context.suggestionStart, suggestion.getRange().getStart()) + suggestion.getText(), tooltip); ++ } ++ ++ private static @NonNull Candidate toCandidate(final @NonNull Completion completion) { ++ return toCandidate(completion.suggestion(), completion.tooltip()); ++ } ++ ++ private static @NonNull Candidate toCandidate(final @NonNull String suggestionText, final @Nullable Component tooltip) { ++ final String suggestionTooltip = PaperAdventure.ANSI_SERIALIZER.serializeOr(tooltip, null); ++ //noinspection SpellCheckingInspection ++ return new PaperCandidate( ++ suggestionText, ++ suggestionText, ++ null, ++ suggestionTooltip, ++ null, ++ null, ++ /* ++ in an ideal world, this would sometimes be true if the suggestion represented the final possible value for a word. ++ Like for `/execute alig`, pressing enter on align would add a trailing space if this value was true. But not all ++ suggestions should add spaces after, like `/execute as @`, accepting any suggestion here would be valid, but its also ++ valid to have a `[` following the selector ++ */ ++ false ++ ); ++ } ++ ++ private static @NonNull Completion toCompletion(final @NonNull Suggestion suggestion) { ++ if (suggestion.getTooltip() == null) { ++ return completion(suggestion.getText()); ++ } ++ return completion(suggestion.getText(), PaperAdventure.asAdventure(ComponentUtils.fromMessage(suggestion.getTooltip()))); ++ } ++ ++ private record ParseContext(String line, int suggestionStart) { ++ } ++ ++ public static final class PaperCandidate extends Candidate { ++ public PaperCandidate(final String value, final String display, final String group, final String descr, final String suffix, final String key, final boolean complete) { ++ super(value, display, group, descr, suffix, key, complete); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0b21dac4473e3ea8022ef5c17f5f7d4d49d3ac0a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java +@@ -0,0 +1,67 @@ ++package io.papermc.paper.console; ++ ++import com.google.common.base.Suppliers; ++import com.mojang.brigadier.ParseResults; ++import com.mojang.brigadier.StringReader; ++import com.mojang.brigadier.context.ParsedCommandNode; ++import com.mojang.brigadier.tree.LiteralCommandNode; ++import java.util.function.Supplier; ++import java.util.regex.Pattern; ++import net.minecraft.commands.CommandSourceStack; ++import net.minecraft.server.dedicated.DedicatedServer; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jline.reader.Highlighter; ++import org.jline.reader.LineReader; ++import org.jline.utils.AttributedString; ++import org.jline.utils.AttributedStringBuilder; ++import org.jline.utils.AttributedStyle; ++ ++public final class BrigadierCommandHighlighter implements Highlighter { ++ private static final int[] COLORS = {AttributedStyle.CYAN, AttributedStyle.YELLOW, AttributedStyle.GREEN, AttributedStyle.MAGENTA, /* Client uses GOLD here, not BLUE, however there is no GOLD AttributedStyle. */ AttributedStyle.BLUE}; ++ private final Supplier commandSourceStack; ++ private final DedicatedServer server; ++ ++ public BrigadierCommandHighlighter(final @NonNull DedicatedServer server) { ++ this.server = server; ++ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack); ++ } ++ ++ @Override ++ public AttributedString highlight(final @NonNull LineReader reader, final @NonNull String buffer) { ++ //noinspection ConstantConditions ++ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet ++ return new AttributedString(buffer, AttributedStyle.DEFAULT.foreground(AttributedStyle.RED)); ++ } ++ final AttributedStringBuilder builder = new AttributedStringBuilder(); ++ final ParseResults results = this.server.getCommands().getDispatcher().parse(new StringReader(buffer), this.commandSourceStack.get()); ++ int pos = 0; ++ int component = -1; ++ for (final ParsedCommandNode node : results.getContext().getLastChild().getNodes()) { ++ if (node.getRange().getStart() >= buffer.length()) { ++ break; ++ } ++ final int start = node.getRange().getStart(); ++ final int end = Math.min(node.getRange().getEnd(), buffer.length()); ++ builder.append(buffer.substring(pos, start), AttributedStyle.DEFAULT); ++ if (node.getNode() instanceof LiteralCommandNode) { ++ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT); ++ } else { ++ if (++component >= COLORS.length) { ++ component = 0; ++ } ++ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT.foreground(COLORS[component])); ++ } ++ pos = end; ++ } ++ if (pos < buffer.length()) { ++ builder.append((buffer.substring(pos)), AttributedStyle.DEFAULT.foreground(AttributedStyle.RED)); ++ } ++ return builder.toAttributedString(); ++ } ++ ++ @Override ++ public void setErrorPattern(final Pattern errorPattern) {} ++ ++ @Override ++ public void setErrorIndex(final int errorIndex) {} ++} +diff --git a/src/main/java/io/papermc/paper/console/BrigadierCompletionMatcher.java b/src/main/java/io/papermc/paper/console/BrigadierCompletionMatcher.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1e8028a43db0ff1d5b22d06ef12c1c32d992c09c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/console/BrigadierCompletionMatcher.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.console; ++ ++import com.google.common.collect.Iterables; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++import org.jline.reader.Candidate; ++import org.jline.reader.CompletingParsedLine; ++import org.jline.reader.LineReader; ++import org.jline.reader.impl.CompletionMatcherImpl; ++ ++public class BrigadierCompletionMatcher extends CompletionMatcherImpl { ++ ++ @Override ++ protected void defaultMatchers(final Map options, final boolean prefix, final CompletingParsedLine line, final boolean caseInsensitive, final int errors, final String originalGroupName) { ++ super.defaultMatchers(options, prefix, line, caseInsensitive, errors, originalGroupName); ++ this.matchers.addFirst(m -> { ++ final Map> candidates = new HashMap<>(); ++ for (final Map.Entry> entry : m.entrySet()) { ++ if (Iterables.all(entry.getValue(), BrigadierCommandCompleter.PaperCandidate.class::isInstance)) { ++ candidates.put(entry.getKey(), entry.getValue()); ++ } ++ } ++ return candidates; ++ }); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/console/BrigadierConsoleParser.java b/src/main/java/io/papermc/paper/console/BrigadierConsoleParser.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8239a8ba57f856cbbee237a601b3cabfce20ba26 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/console/BrigadierConsoleParser.java +@@ -0,0 +1,79 @@ ++package io.papermc.paper.console; ++ ++import com.mojang.brigadier.ImmutableStringReader; ++import com.mojang.brigadier.ParseResults; ++import com.mojang.brigadier.StringReader; ++import com.mojang.brigadier.context.CommandContextBuilder; ++import com.mojang.brigadier.context.ParsedCommandNode; ++import com.mojang.brigadier.context.StringRange; ++import java.util.ArrayList; ++import java.util.List; ++import net.minecraft.commands.CommandSourceStack; ++import net.minecraft.server.dedicated.DedicatedServer; ++import org.jline.reader.ParsedLine; ++import org.jline.reader.Parser; ++import org.jline.reader.SyntaxError; ++ ++public class BrigadierConsoleParser implements Parser { ++ ++ private final DedicatedServer server; ++ ++ public BrigadierConsoleParser(DedicatedServer server) { ++ this.server = server; ++ } ++ ++ @Override ++ public ParsedLine parse(final String line, final int cursor, final ParseContext context) throws SyntaxError { ++ final ParseResults results = this.server.getCommands().getDispatcher().parse(new StringReader(line), this.server.createCommandSourceStack()); ++ final ImmutableStringReader reader = results.getReader(); ++ final List words = new ArrayList<>(); ++ CommandContextBuilder currentContext = results.getContext(); ++ int currentWordIdx = -1; ++ int wordIdx = -1; ++ int inWordCursor = -1; ++ if (currentContext.getRange().getLength() > 0) { ++ do { ++ for (final ParsedCommandNode node : currentContext.getNodes()) { ++ final StringRange nodeRange = node.getRange(); ++ String current = nodeRange.get(reader); ++ words.add(current); ++ currentWordIdx++; ++ if (wordIdx == -1 && nodeRange.getStart() <= cursor && nodeRange.getEnd() >= cursor) { ++ // if cursor is in the middle of a parsed word/node ++ wordIdx = currentWordIdx; ++ inWordCursor = cursor - nodeRange.getStart(); ++ } ++ } ++ currentContext = currentContext.getChild(); ++ } while (currentContext != null); ++ } ++ final String leftovers = reader.getRemaining(); ++ if (!leftovers.isEmpty() && leftovers.isBlank()) { ++ // if brig didn't consume the whole line, and everything else is blank, add a new empty word ++ currentWordIdx++; ++ words.add(""); ++ if (wordIdx == -1) { ++ wordIdx = currentWordIdx; ++ inWordCursor = 0; ++ } ++ } else if (!leftovers.isEmpty()) { ++ // if there are unparsed leftovers, add a new word with the remaining input ++ currentWordIdx++; ++ words.add(leftovers); ++ if (wordIdx == -1) { ++ wordIdx = currentWordIdx; ++ inWordCursor = cursor - reader.getCursor(); ++ } ++ } ++ if (wordIdx == -1) { ++ currentWordIdx++; ++ words.add(""); ++ wordIdx = currentWordIdx; ++ inWordCursor = 0; ++ } ++ return new BrigadierParsedLine(words.get(wordIdx), inWordCursor, wordIdx, words, line, cursor); ++ } ++ ++ record BrigadierParsedLine(String word, int wordCursor, int wordIndex, List words, String line, int cursor) implements ParsedLine { ++ } ++} +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 9d05e998d6df1069c2de69478a1f9688ac435e67..7c92b2f0a59fe222ad13a998476e312bf571a1bf 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -187,7 +187,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + + thread.setDaemon(true); + thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER)); +- thread.start(); ++ // thread.start(); // Paper - Enhance console tab completions for brigadier commands; moved down + DedicatedServer.LOGGER.info("Starting minecraft server version {}", SharedConstants.getCurrentVersion().getName()); + if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) { + DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); +@@ -220,6 +220,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames + // Paper end - fix converting txt to json file + org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread ++ thread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized + io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command + com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics + com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now +diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java +index 15bc85f4799a4b23edd2f1e93f1794de5ca3e8e3..a45e658996e483e9a21cfd8178153ddb7b87ae69 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java +@@ -18,9 +18,11 @@ import org.bukkit.event.server.TabCompleteEvent; + + public class ConsoleCommandCompleter implements Completer { + private final DedicatedServer server; // Paper - CraftServer -> DedicatedServer ++ private final io.papermc.paper.console.BrigadierCommandCompleter brigadierCompleter; // Paper - Enhance console tab completions for brigadier commands + + public ConsoleCommandCompleter(DedicatedServer server) { // Paper - CraftServer -> DedicatedServer + this.server = server; ++ this.brigadierCompleter = new io.papermc.paper.console.BrigadierCommandCompleter(this.server); // Paper - Enhance console tab completions for brigadier commands + } + + // Paper start - Change method signature for JLine update +@@ -64,7 +66,7 @@ public class ConsoleCommandCompleter implements Completer { + } + } + +- if (!completions.isEmpty()) { ++ if (false && !completions.isEmpty()) { + for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion completion : completions) { + if (completion.suggestion().isEmpty()) { + continue; +@@ -80,6 +82,7 @@ public class ConsoleCommandCompleter implements Completer { + )); + } + } ++ this.addCompletions(reader, line, candidates, completions); + return; + } + +@@ -99,10 +102,12 @@ public class ConsoleCommandCompleter implements Completer { + try { + List offers = waitable.get(); + if (offers == null) { ++ this.addCompletions(reader, line, candidates, Collections.emptyList()); // Paper - Enhance console tab completions for brigadier commands + return; // Paper - Method returns void + } + + // Paper start - JLine update ++ /* + for (String completion : offers) { + if (completion.isEmpty()) { + continue; +@@ -110,6 +115,8 @@ public class ConsoleCommandCompleter implements Completer { + + candidates.add(new Candidate(completion)); + } ++ */ ++ this.addCompletions(reader, line, candidates, offers.stream().map(com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion::completion).collect(java.util.stream.Collectors.toList())); + // Paper end + + // Paper start - JLine handles cursor now +@@ -138,5 +145,9 @@ public class ConsoleCommandCompleter implements Completer { + } + return false; + } ++ ++ private void addCompletions(final LineReader reader, final ParsedLine line, final List candidates, final List existing) { ++ this.brigadierCompleter.complete(reader, line, candidates, existing); ++ } + // Paper end + } diff --git a/patches/server/0498-Expose-protocol-version.patch b/patches/server/0498-Expose-protocol-version.patch deleted file mode 100644 index cd6a7ab2b0..0000000000 --- a/patches/server/0498-Expose-protocol-version.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Fri, 26 Mar 2021 11:23:17 +0100 -Subject: [PATCH] Expose protocol version - - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 8d9380b50424546bcebdfa868635f94c8efa5899..30f2ddb66385718304b4b0302f7efcafd54bc42a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -543,6 +543,11 @@ public final class CraftMagicNumbers implements UnsafeValues { - public String getMainLevelName() { - return ((net.minecraft.server.dedicated.DedicatedServer) net.minecraft.server.MinecraftServer.getServer()).getProperties().levelName; - } -+ -+ @Override -+ public int getProtocolVersion() { -+ return net.minecraft.SharedConstants.getCurrentVersion().getProtocolVersion(); -+ } - // Paper end - - /** diff --git a/patches/server/0499-Enhance-console-tab-completions-for-brigadier-comman.patch b/patches/server/0499-Enhance-console-tab-completions-for-brigadier-comman.patch deleted file mode 100644 index 3d1a0fb945..0000000000 --- a/patches/server/0499-Enhance-console-tab-completions-for-brigadier-comman.patch +++ /dev/null @@ -1,445 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Tue, 30 Mar 2021 16:06:08 -0700 -Subject: [PATCH] Enhance console tab completions for brigadier commands - -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java -index a4070b59e261f0f1ac4beec47b11492f4724bf27..6ee39b534b8d992655bc0cef3c299d12cbae0034 100644 ---- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java -+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java -@@ -1,5 +1,8 @@ - package com.destroystokyo.paper.console; - -+import io.papermc.paper.configuration.GlobalConfiguration; -+import io.papermc.paper.console.BrigadierCompletionMatcher; -+import io.papermc.paper.console.BrigadierConsoleParser; - import net.minecraft.server.dedicated.DedicatedServer; - import net.minecrell.terminalconsole.SimpleTerminalConsole; - import org.bukkit.craftbukkit.command.ConsoleCommandCompleter; -@@ -16,11 +19,20 @@ public final class PaperConsole extends SimpleTerminalConsole { - - @Override - protected LineReader buildReader(LineReaderBuilder builder) { -- return super.buildReader(builder -+ builder - .appName("Paper") - .variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history")) - .completer(new ConsoleCommandCompleter(this.server)) -- ); -+ .option(LineReader.Option.COMPLETE_IN_WORD, true); -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierHighlighting) { -+ builder.highlighter(new io.papermc.paper.console.BrigadierCommandHighlighter(this.server)); -+ } -+ if (GlobalConfiguration.get().console.enableBrigadierCompletions) { -+ System.setProperty("org.jline.reader.support.parsedline", "true"); // to hide a warning message about the parser not supporting -+ builder.parser(new BrigadierConsoleParser(this.server)); -+ builder.completionMatcher(new BrigadierCompletionMatcher()); -+ } -+ return super.buildReader(builder); - } - - @Override -diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bf7b9518c05ff8a6d4b7d7cd36187ca22257e3dc ---- /dev/null -+++ b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java -@@ -0,0 +1,119 @@ -+package io.papermc.paper.console; -+ -+import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent; -+import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion; -+import com.google.common.base.Suppliers; -+import com.mojang.brigadier.CommandDispatcher; -+import com.mojang.brigadier.ParseResults; -+import com.mojang.brigadier.StringReader; -+import com.mojang.brigadier.suggestion.Suggestion; -+import io.papermc.paper.adventure.PaperAdventure; -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.List; -+import java.util.function.Supplier; -+import net.kyori.adventure.text.Component; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.network.chat.ComponentUtils; -+import net.minecraft.server.dedicated.DedicatedServer; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.jline.reader.Candidate; -+import org.jline.reader.LineReader; -+import org.jline.reader.ParsedLine; -+ -+import static com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion.completion; -+ -+public final class BrigadierCommandCompleter { -+ private final Supplier commandSourceStack; -+ private final DedicatedServer server; -+ -+ public BrigadierCommandCompleter(final @NonNull DedicatedServer server) { -+ this.server = server; -+ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack); -+ } -+ -+ public void complete(final @NonNull LineReader reader, final @NonNull ParsedLine line, final @NonNull List candidates, final @NonNull List existing) { -+ //noinspection ConstantConditions -+ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet -+ return; -+ } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierCompletions) { -+ this.addCandidates(candidates, Collections.emptyList(), existing, new ParseContext(line.line(), 0)); -+ return; -+ } -+ final CommandDispatcher dispatcher = this.server.getCommands().getDispatcher(); -+ final ParseResults results = dispatcher.parse(new StringReader(line.line()), this.commandSourceStack.get()); -+ this.addCandidates( -+ candidates, -+ dispatcher.getCompletionSuggestions(results, line.cursor()).join().getList(), -+ existing, -+ new ParseContext(line.line(), results.getContext().findSuggestionContext(line.cursor()).startPos) -+ ); -+ } -+ -+ private void addCandidates( -+ final @NonNull List candidates, -+ final @NonNull List brigSuggestions, -+ final @NonNull List existing, -+ final @NonNull ParseContext context -+ ) { -+ brigSuggestions.forEach(it -> { -+ if (it.getText().isEmpty()) return; -+ candidates.add(toCandidate(it, context)); -+ }); -+ for (final AsyncTabCompleteEvent.Completion completion : existing) { -+ if (completion.suggestion().isEmpty() || brigSuggestions.stream().anyMatch(it -> it.getText().equals(completion.suggestion()))) { -+ continue; -+ } -+ candidates.add(toCandidate(completion)); -+ } -+ } -+ -+ private static Candidate toCandidate(final Suggestion suggestion, final @NonNull ParseContext context) { -+ Component tooltip = null; -+ if (suggestion.getTooltip() != null) { -+ tooltip = PaperAdventure.asAdventure(ComponentUtils.fromMessage(suggestion.getTooltip())); -+ } -+ return toCandidate(context.line.substring(context.suggestionStart, suggestion.getRange().getStart()) + suggestion.getText(), tooltip); -+ } -+ -+ private static @NonNull Candidate toCandidate(final @NonNull Completion completion) { -+ return toCandidate(completion.suggestion(), completion.tooltip()); -+ } -+ -+ private static @NonNull Candidate toCandidate(final @NonNull String suggestionText, final @Nullable Component tooltip) { -+ final String suggestionTooltip = PaperAdventure.ANSI_SERIALIZER.serializeOr(tooltip, null); -+ //noinspection SpellCheckingInspection -+ return new PaperCandidate( -+ suggestionText, -+ suggestionText, -+ null, -+ suggestionTooltip, -+ null, -+ null, -+ /* -+ in an ideal world, this would sometimes be true if the suggestion represented the final possible value for a word. -+ Like for `/execute alig`, pressing enter on align would add a trailing space if this value was true. But not all -+ suggestions should add spaces after, like `/execute as @`, accepting any suggestion here would be valid, but its also -+ valid to have a `[` following the selector -+ */ -+ false -+ ); -+ } -+ -+ private static @NonNull Completion toCompletion(final @NonNull Suggestion suggestion) { -+ if (suggestion.getTooltip() == null) { -+ return completion(suggestion.getText()); -+ } -+ return completion(suggestion.getText(), PaperAdventure.asAdventure(ComponentUtils.fromMessage(suggestion.getTooltip()))); -+ } -+ -+ private record ParseContext(String line, int suggestionStart) { -+ } -+ -+ public static final class PaperCandidate extends Candidate { -+ public PaperCandidate(final String value, final String display, final String group, final String descr, final String suffix, final String key, final boolean complete) { -+ super(value, display, group, descr, suffix, key, complete); -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0b21dac4473e3ea8022ef5c17f5f7d4d49d3ac0a ---- /dev/null -+++ b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java -@@ -0,0 +1,67 @@ -+package io.papermc.paper.console; -+ -+import com.google.common.base.Suppliers; -+import com.mojang.brigadier.ParseResults; -+import com.mojang.brigadier.StringReader; -+import com.mojang.brigadier.context.ParsedCommandNode; -+import com.mojang.brigadier.tree.LiteralCommandNode; -+import java.util.function.Supplier; -+import java.util.regex.Pattern; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.server.dedicated.DedicatedServer; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.jline.reader.Highlighter; -+import org.jline.reader.LineReader; -+import org.jline.utils.AttributedString; -+import org.jline.utils.AttributedStringBuilder; -+import org.jline.utils.AttributedStyle; -+ -+public final class BrigadierCommandHighlighter implements Highlighter { -+ private static final int[] COLORS = {AttributedStyle.CYAN, AttributedStyle.YELLOW, AttributedStyle.GREEN, AttributedStyle.MAGENTA, /* Client uses GOLD here, not BLUE, however there is no GOLD AttributedStyle. */ AttributedStyle.BLUE}; -+ private final Supplier commandSourceStack; -+ private final DedicatedServer server; -+ -+ public BrigadierCommandHighlighter(final @NonNull DedicatedServer server) { -+ this.server = server; -+ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack); -+ } -+ -+ @Override -+ public AttributedString highlight(final @NonNull LineReader reader, final @NonNull String buffer) { -+ //noinspection ConstantConditions -+ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet -+ return new AttributedString(buffer, AttributedStyle.DEFAULT.foreground(AttributedStyle.RED)); -+ } -+ final AttributedStringBuilder builder = new AttributedStringBuilder(); -+ final ParseResults results = this.server.getCommands().getDispatcher().parse(new StringReader(buffer), this.commandSourceStack.get()); -+ int pos = 0; -+ int component = -1; -+ for (final ParsedCommandNode node : results.getContext().getLastChild().getNodes()) { -+ if (node.getRange().getStart() >= buffer.length()) { -+ break; -+ } -+ final int start = node.getRange().getStart(); -+ final int end = Math.min(node.getRange().getEnd(), buffer.length()); -+ builder.append(buffer.substring(pos, start), AttributedStyle.DEFAULT); -+ if (node.getNode() instanceof LiteralCommandNode) { -+ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT); -+ } else { -+ if (++component >= COLORS.length) { -+ component = 0; -+ } -+ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT.foreground(COLORS[component])); -+ } -+ pos = end; -+ } -+ if (pos < buffer.length()) { -+ builder.append((buffer.substring(pos)), AttributedStyle.DEFAULT.foreground(AttributedStyle.RED)); -+ } -+ return builder.toAttributedString(); -+ } -+ -+ @Override -+ public void setErrorPattern(final Pattern errorPattern) {} -+ -+ @Override -+ public void setErrorIndex(final int errorIndex) {} -+} -diff --git a/src/main/java/io/papermc/paper/console/BrigadierCompletionMatcher.java b/src/main/java/io/papermc/paper/console/BrigadierCompletionMatcher.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1e8028a43db0ff1d5b22d06ef12c1c32d992c09c ---- /dev/null -+++ b/src/main/java/io/papermc/paper/console/BrigadierCompletionMatcher.java -@@ -0,0 +1,27 @@ -+package io.papermc.paper.console; -+ -+import com.google.common.collect.Iterables; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+import org.jline.reader.Candidate; -+import org.jline.reader.CompletingParsedLine; -+import org.jline.reader.LineReader; -+import org.jline.reader.impl.CompletionMatcherImpl; -+ -+public class BrigadierCompletionMatcher extends CompletionMatcherImpl { -+ -+ @Override -+ protected void defaultMatchers(final Map options, final boolean prefix, final CompletingParsedLine line, final boolean caseInsensitive, final int errors, final String originalGroupName) { -+ super.defaultMatchers(options, prefix, line, caseInsensitive, errors, originalGroupName); -+ this.matchers.addFirst(m -> { -+ final Map> candidates = new HashMap<>(); -+ for (final Map.Entry> entry : m.entrySet()) { -+ if (Iterables.all(entry.getValue(), BrigadierCommandCompleter.PaperCandidate.class::isInstance)) { -+ candidates.put(entry.getKey(), entry.getValue()); -+ } -+ } -+ return candidates; -+ }); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/console/BrigadierConsoleParser.java b/src/main/java/io/papermc/paper/console/BrigadierConsoleParser.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8239a8ba57f856cbbee237a601b3cabfce20ba26 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/console/BrigadierConsoleParser.java -@@ -0,0 +1,79 @@ -+package io.papermc.paper.console; -+ -+import com.mojang.brigadier.ImmutableStringReader; -+import com.mojang.brigadier.ParseResults; -+import com.mojang.brigadier.StringReader; -+import com.mojang.brigadier.context.CommandContextBuilder; -+import com.mojang.brigadier.context.ParsedCommandNode; -+import com.mojang.brigadier.context.StringRange; -+import java.util.ArrayList; -+import java.util.List; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.server.dedicated.DedicatedServer; -+import org.jline.reader.ParsedLine; -+import org.jline.reader.Parser; -+import org.jline.reader.SyntaxError; -+ -+public class BrigadierConsoleParser implements Parser { -+ -+ private final DedicatedServer server; -+ -+ public BrigadierConsoleParser(DedicatedServer server) { -+ this.server = server; -+ } -+ -+ @Override -+ public ParsedLine parse(final String line, final int cursor, final ParseContext context) throws SyntaxError { -+ final ParseResults results = this.server.getCommands().getDispatcher().parse(new StringReader(line), this.server.createCommandSourceStack()); -+ final ImmutableStringReader reader = results.getReader(); -+ final List words = new ArrayList<>(); -+ CommandContextBuilder currentContext = results.getContext(); -+ int currentWordIdx = -1; -+ int wordIdx = -1; -+ int inWordCursor = -1; -+ if (currentContext.getRange().getLength() > 0) { -+ do { -+ for (final ParsedCommandNode node : currentContext.getNodes()) { -+ final StringRange nodeRange = node.getRange(); -+ String current = nodeRange.get(reader); -+ words.add(current); -+ currentWordIdx++; -+ if (wordIdx == -1 && nodeRange.getStart() <= cursor && nodeRange.getEnd() >= cursor) { -+ // if cursor is in the middle of a parsed word/node -+ wordIdx = currentWordIdx; -+ inWordCursor = cursor - nodeRange.getStart(); -+ } -+ } -+ currentContext = currentContext.getChild(); -+ } while (currentContext != null); -+ } -+ final String leftovers = reader.getRemaining(); -+ if (!leftovers.isEmpty() && leftovers.isBlank()) { -+ // if brig didn't consume the whole line, and everything else is blank, add a new empty word -+ currentWordIdx++; -+ words.add(""); -+ if (wordIdx == -1) { -+ wordIdx = currentWordIdx; -+ inWordCursor = 0; -+ } -+ } else if (!leftovers.isEmpty()) { -+ // if there are unparsed leftovers, add a new word with the remaining input -+ currentWordIdx++; -+ words.add(leftovers); -+ if (wordIdx == -1) { -+ wordIdx = currentWordIdx; -+ inWordCursor = cursor - reader.getCursor(); -+ } -+ } -+ if (wordIdx == -1) { -+ currentWordIdx++; -+ words.add(""); -+ wordIdx = currentWordIdx; -+ inWordCursor = 0; -+ } -+ return new BrigadierParsedLine(words.get(wordIdx), inWordCursor, wordIdx, words, line, cursor); -+ } -+ -+ record BrigadierParsedLine(String word, int wordCursor, int wordIndex, List words, String line, int cursor) implements ParsedLine { -+ } -+} -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 9d05e998d6df1069c2de69478a1f9688ac435e67..7c92b2f0a59fe222ad13a998476e312bf571a1bf 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -187,7 +187,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - - thread.setDaemon(true); - thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER)); -- thread.start(); -+ // thread.start(); // Paper - Enhance console tab completions for brigadier commands; moved down - DedicatedServer.LOGGER.info("Starting minecraft server version {}", SharedConstants.getCurrentVersion().getName()); - if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) { - DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); -@@ -220,6 +220,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames - // Paper end - fix converting txt to json file - org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread -+ thread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized - io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command - com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics - com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now -diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java -index 15bc85f4799a4b23edd2f1e93f1794de5ca3e8e3..a45e658996e483e9a21cfd8178153ddb7b87ae69 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java -@@ -18,9 +18,11 @@ import org.bukkit.event.server.TabCompleteEvent; - - public class ConsoleCommandCompleter implements Completer { - private final DedicatedServer server; // Paper - CraftServer -> DedicatedServer -+ private final io.papermc.paper.console.BrigadierCommandCompleter brigadierCompleter; // Paper - Enhance console tab completions for brigadier commands - - public ConsoleCommandCompleter(DedicatedServer server) { // Paper - CraftServer -> DedicatedServer - this.server = server; -+ this.brigadierCompleter = new io.papermc.paper.console.BrigadierCommandCompleter(this.server); // Paper - Enhance console tab completions for brigadier commands - } - - // Paper start - Change method signature for JLine update -@@ -64,7 +66,7 @@ public class ConsoleCommandCompleter implements Completer { - } - } - -- if (!completions.isEmpty()) { -+ if (false && !completions.isEmpty()) { - for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion completion : completions) { - if (completion.suggestion().isEmpty()) { - continue; -@@ -80,6 +82,7 @@ public class ConsoleCommandCompleter implements Completer { - )); - } - } -+ this.addCompletions(reader, line, candidates, completions); - return; - } - -@@ -99,10 +102,12 @@ public class ConsoleCommandCompleter implements Completer { - try { - List offers = waitable.get(); - if (offers == null) { -+ this.addCompletions(reader, line, candidates, Collections.emptyList()); // Paper - Enhance console tab completions for brigadier commands - return; // Paper - Method returns void - } - - // Paper start - JLine update -+ /* - for (String completion : offers) { - if (completion.isEmpty()) { - continue; -@@ -110,6 +115,8 @@ public class ConsoleCommandCompleter implements Completer { - - candidates.add(new Candidate(completion)); - } -+ */ -+ this.addCompletions(reader, line, candidates, offers.stream().map(com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion::completion).collect(java.util.stream.Collectors.toList())); - // Paper end - - // Paper start - JLine handles cursor now -@@ -138,5 +145,9 @@ public class ConsoleCommandCompleter implements Completer { - } - return false; - } -+ -+ private void addCompletions(final LineReader reader, final ParsedLine line, final List candidates, final List existing) { -+ this.brigadierCompleter.complete(reader, line, candidates, existing); -+ } - // Paper end - } diff --git a/patches/server/0499-Fix-PlayerItemConsumeEvent-cancelling-properly.patch b/patches/server/0499-Fix-PlayerItemConsumeEvent-cancelling-properly.patch new file mode 100644 index 0000000000..ce126cbfd4 --- /dev/null +++ b/patches/server/0499-Fix-PlayerItemConsumeEvent-cancelling-properly.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chickeneer +Date: Fri, 19 Mar 2021 00:33:15 -0500 +Subject: [PATCH] Fix PlayerItemConsumeEvent cancelling properly + +When the active item is not cleared, the item is still readied +for use and will repeatedly trigger the PlayerItemConsumeEvent +till their item is switched. +This patch clears the active item when the event is cancelled + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 728004ca0c0e0ce40f2357ed8dc5f2a86b9cc50a..fc51c7ed9b60a307562c81475ef1cedcb1605798 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -4149,6 +4149,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + entityPlayer.getBukkitEntity().updateInventory(); + entityPlayer.getBukkitEntity().updateScaledHealth(); ++ this.stopUsingItem(); // Paper - event is using an item, clear active item to reset its use + return; + } + diff --git a/patches/server/0500-Add-bypass-host-check.patch b/patches/server/0500-Add-bypass-host-check.patch new file mode 100644 index 0000000000..53fea6e14d --- /dev/null +++ b/patches/server/0500-Add-bypass-host-check.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Sun, 18 Apr 2021 21:27:01 +0100 +Subject: [PATCH] Add bypass host check + +Paper.bypassHostCheck + +Seriously, fix your firewalls. -.- + +diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java +index 0c1bdf2329936ce479a2cc53e8a46bd2ad685ec1..a5bbea6a073e00c10c3c5facd997eb8473fd9a5f 100644 +--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java +@@ -32,6 +32,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL + private static final Component IGNORE_STATUS_REASON = Component.translatable("disconnect.ignoring_status_request"); + private final MinecraftServer server; + private final Connection connection; ++ private static final boolean BYPASS_HOSTCHECK = Boolean.getBoolean("Paper.bypassHostCheck"); // Paper + + public ServerHandshakePacketListenerImpl(MinecraftServer server, Connection connection) { + this.server = server; +@@ -164,7 +165,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL + String[] split = packet.hostName().split("\00"); + if (!handledByEvent && proxyLogicEnabled) { // Paper + // if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above! +- if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) { ++ if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.BYPASS_HOSTCHECK || ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) { // Paper - Add bypass host check + this.connection.hostname = split[0]; + this.connection.address = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getPort()); + this.connection.spoofedUUID = com.mojang.util.UndashedUuid.fromStringLenient( split[2] ); diff --git a/patches/server/0500-Fix-PlayerItemConsumeEvent-cancelling-properly.patch b/patches/server/0500-Fix-PlayerItemConsumeEvent-cancelling-properly.patch deleted file mode 100644 index ce126cbfd4..0000000000 --- a/patches/server/0500-Fix-PlayerItemConsumeEvent-cancelling-properly.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: chickeneer -Date: Fri, 19 Mar 2021 00:33:15 -0500 -Subject: [PATCH] Fix PlayerItemConsumeEvent cancelling properly - -When the active item is not cleared, the item is still readied -for use and will repeatedly trigger the PlayerItemConsumeEvent -till their item is switched. -This patch clears the active item when the event is cancelled - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 728004ca0c0e0ce40f2357ed8dc5f2a86b9cc50a..fc51c7ed9b60a307562c81475ef1cedcb1605798 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -4149,6 +4149,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - entityPlayer.getBukkitEntity().updateInventory(); - entityPlayer.getBukkitEntity().updateScaledHealth(); -+ this.stopUsingItem(); // Paper - event is using an item, clear active item to reset its use - return; - } - diff --git a/patches/server/0501-Add-bypass-host-check.patch b/patches/server/0501-Add-bypass-host-check.patch deleted file mode 100644 index 53fea6e14d..0000000000 --- a/patches/server/0501-Add-bypass-host-check.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Sun, 18 Apr 2021 21:27:01 +0100 -Subject: [PATCH] Add bypass host check - -Paper.bypassHostCheck - -Seriously, fix your firewalls. -.- - -diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java -index 0c1bdf2329936ce479a2cc53e8a46bd2ad685ec1..a5bbea6a073e00c10c3c5facd997eb8473fd9a5f 100644 ---- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java -@@ -32,6 +32,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL - private static final Component IGNORE_STATUS_REASON = Component.translatable("disconnect.ignoring_status_request"); - private final MinecraftServer server; - private final Connection connection; -+ private static final boolean BYPASS_HOSTCHECK = Boolean.getBoolean("Paper.bypassHostCheck"); // Paper - - public ServerHandshakePacketListenerImpl(MinecraftServer server, Connection connection) { - this.server = server; -@@ -164,7 +165,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL - String[] split = packet.hostName().split("\00"); - if (!handledByEvent && proxyLogicEnabled) { // Paper - // if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above! -- if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) { -+ if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.BYPASS_HOSTCHECK || ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) { // Paper - Add bypass host check - this.connection.hostname = split[0]; - this.connection.address = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getPort()); - this.connection.spoofedUUID = com.mojang.util.UndashedUuid.fromStringLenient( split[2] ); diff --git a/patches/server/0501-Set-area-affect-cloud-rotation.patch b/patches/server/0501-Set-area-affect-cloud-rotation.patch new file mode 100644 index 0000000000..92bb3dc84a --- /dev/null +++ b/patches/server/0501-Set-area-affect-cloud-rotation.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Mon, 5 Apr 2021 16:58:20 -0400 +Subject: [PATCH] Set area affect cloud rotation + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +index 0ebcf7ed1cb9e896de5fbac60afdb937ba86d15c..95c2ef53e6c5574e69614d8058eb3ed94ab6b0d6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -426,7 +426,7 @@ public final class CraftEntityTypes { + 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 + )); +- register(new EntityTypeData<>(EntityType.AREA_EFFECT_CLOUD, AreaEffectCloud.class, CraftAreaEffectCloud::new, spawnData -> new net.minecraft.world.entity.AreaEffectCloud(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); ++ 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)))); + register(new EntityTypeData<>(EntityType.LEASH_KNOT, LeashHitch.class, CraftLeash::new, spawnData -> new LeashFenceKnotEntity(spawnData.minecraftWorld(), BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z())))); // SPIGOT-5732: LeashHitch has no direction and is always centered at a block + register(new EntityTypeData<>(EntityType.SNOWBALL, Snowball.class, CraftSnowball::new, spawnData -> new net.minecraft.world.entity.projectile.Snowball(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), new net.minecraft.world.item.ItemStack(Items.SNOWBALL)))); diff --git a/patches/server/0502-Set-area-affect-cloud-rotation.patch b/patches/server/0502-Set-area-affect-cloud-rotation.patch deleted file mode 100644 index 92bb3dc84a..0000000000 --- a/patches/server/0502-Set-area-affect-cloud-rotation.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: Mon, 5 Apr 2021 16:58:20 -0400 -Subject: [PATCH] Set area affect cloud rotation - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -index 0ebcf7ed1cb9e896de5fbac60afdb937ba86d15c..95c2ef53e6c5574e69614d8058eb3ed94ab6b0d6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -426,7 +426,7 @@ public final class CraftEntityTypes { - 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 - )); -- register(new EntityTypeData<>(EntityType.AREA_EFFECT_CLOUD, AreaEffectCloud.class, CraftAreaEffectCloud::new, spawnData -> new net.minecraft.world.entity.AreaEffectCloud(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); -+ 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)))); - register(new EntityTypeData<>(EntityType.LEASH_KNOT, LeashHitch.class, CraftLeash::new, spawnData -> new LeashFenceKnotEntity(spawnData.minecraftWorld(), BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z())))); // SPIGOT-5732: LeashHitch has no direction and is always centered at a block - register(new EntityTypeData<>(EntityType.SNOWBALL, Snowball.class, CraftSnowball::new, spawnData -> new net.minecraft.world.entity.projectile.Snowball(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), new net.minecraft.world.item.ItemStack(Items.SNOWBALL)))); diff --git a/patches/server/0502-add-isDeeplySleeping-to-HumanEntity.patch b/patches/server/0502-add-isDeeplySleeping-to-HumanEntity.patch new file mode 100644 index 0000000000..645f1201ea --- /dev/null +++ b/patches/server/0502-add-isDeeplySleeping-to-HumanEntity.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 8 Apr 2021 17:36:10 -0700 +Subject: [PATCH] add isDeeplySleeping to HumanEntity + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +index 42c41cd4b280839a35f77e04d0dc6a06d262d8f3..d5c4184e0d93eabc699661829ff4bf9b46d27142 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -132,6 +132,13 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + } + // Paper end + ++ // Paper start ++ @Override ++ public boolean isDeeplySleeping() { ++ return getHandle().isSleepingLongEnough(); ++ } ++ // Paper end ++ + @Override + public int getSleepTicks() { + return this.getHandle().sleepCounter; diff --git a/patches/server/0503-add-consumeFuel-to-FurnaceBurnEvent.patch b/patches/server/0503-add-consumeFuel-to-FurnaceBurnEvent.patch new file mode 100644 index 0000000000..150b4fe7c0 --- /dev/null +++ b/patches/server/0503-add-consumeFuel-to-FurnaceBurnEvent.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 22 Apr 2021 16:45:28 -0700 +Subject: [PATCH] add consumeFuel to FurnaceBurnEvent + + +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 4acf487f9a5f3fa828ee76f9708d6a2ae28707e1..7b63e2fd004ae452c7350f0b2d8d7c57a42891ea 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 +@@ -250,7 +250,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit + if (blockEntity.isLit() && furnaceBurnEvent.isBurning()) { + // CraftBukkit end + flag1 = true; +- if (flag3) { ++ if (flag3 && furnaceBurnEvent.willConsumeFuel()) { // Paper - add consumeFuel to FurnaceBurnEvent + Item item = itemstack.getItem(); + + itemstack.shrink(1); diff --git a/patches/server/0503-add-isDeeplySleeping-to-HumanEntity.patch b/patches/server/0503-add-isDeeplySleeping-to-HumanEntity.patch deleted file mode 100644 index 645f1201ea..0000000000 --- a/patches/server/0503-add-isDeeplySleeping-to-HumanEntity.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 8 Apr 2021 17:36:10 -0700 -Subject: [PATCH] add isDeeplySleeping to HumanEntity - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 42c41cd4b280839a35f77e04d0dc6a06d262d8f3..d5c4184e0d93eabc699661829ff4bf9b46d27142 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -132,6 +132,13 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - } - // Paper end - -+ // Paper start -+ @Override -+ public boolean isDeeplySleeping() { -+ return getHandle().isSleepingLongEnough(); -+ } -+ // Paper end -+ - @Override - public int getSleepTicks() { - return this.getHandle().sleepCounter; diff --git a/patches/server/0504-add-consumeFuel-to-FurnaceBurnEvent.patch b/patches/server/0504-add-consumeFuel-to-FurnaceBurnEvent.patch deleted file mode 100644 index 150b4fe7c0..0000000000 --- a/patches/server/0504-add-consumeFuel-to-FurnaceBurnEvent.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 22 Apr 2021 16:45:28 -0700 -Subject: [PATCH] add consumeFuel to FurnaceBurnEvent - - -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 4acf487f9a5f3fa828ee76f9708d6a2ae28707e1..7b63e2fd004ae452c7350f0b2d8d7c57a42891ea 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 -@@ -250,7 +250,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - if (blockEntity.isLit() && furnaceBurnEvent.isBurning()) { - // CraftBukkit end - flag1 = true; -- if (flag3) { -+ if (flag3 && furnaceBurnEvent.willConsumeFuel()) { // Paper - add consumeFuel to FurnaceBurnEvent - Item item = itemstack.getItem(); - - itemstack.shrink(1); diff --git a/patches/server/0504-add-get-set-drop-chance-to-EntityEquipment.patch b/patches/server/0504-add-get-set-drop-chance-to-EntityEquipment.patch new file mode 100644 index 0000000000..e794470410 --- /dev/null +++ b/patches/server/0504-add-get-set-drop-chance-to-EntityEquipment.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 22 Apr 2021 00:28:11 -0700 +Subject: [PATCH] add get-set drop chance to EntityEquipment + +== AT == +public net.minecraft.world.entity.Mob getEquipmentDropChance(Lnet/minecraft/world/entity/EquipmentSlot;)F + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java +index cb704cef3845727c465fe3ea7210a11545da56c8..fdcc414f4fa246082ad0732133c870d915ae3084 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java +@@ -244,15 +244,22 @@ public class CraftEntityEquipment implements EntityEquipment { + public void setBootsDropChance(float chance) { + this.setDropChance(net.minecraft.world.entity.EquipmentSlot.FEET, chance); + } ++ // Paper start ++ @Override ++ public float getDropChance(EquipmentSlot slot) { ++ return getDropChance(CraftEquipmentSlot.getNMS(slot)); ++ } ++ ++ @Override ++ public void setDropChance(EquipmentSlot slot, float chance) { ++ setDropChance(CraftEquipmentSlot.getNMS(slot), chance); ++ } ++ // Paper end + + private void setDropChance(net.minecraft.world.entity.EquipmentSlot slot, float chance) { + Preconditions.checkArgument(this.entity.getHandle() instanceof Mob, "Cannot set drop chance for non-Mob entity"); + +- if (slot == net.minecraft.world.entity.EquipmentSlot.MAINHAND || slot == net.minecraft.world.entity.EquipmentSlot.OFFHAND) { +- ((Mob) this.entity.getHandle()).handDropChances[slot.getIndex()] = chance; +- } else { +- ((Mob) this.entity.getHandle()).armorDropChances[slot.getIndex()] = chance; +- } ++ ((Mob) this.entity.getHandle()).setDropChance(slot, chance); // Paper - use setter on Mob + } + + private float getDropChance(net.minecraft.world.entity.EquipmentSlot slot) { +@@ -260,10 +267,6 @@ public class CraftEntityEquipment implements EntityEquipment { + return 1; + } + +- if (slot == net.minecraft.world.entity.EquipmentSlot.MAINHAND || slot == net.minecraft.world.entity.EquipmentSlot.OFFHAND) { +- return ((Mob) this.entity.getHandle()).handDropChances[slot.getIndex()]; +- } else { +- return ((Mob) this.entity.getHandle()).armorDropChances[slot.getIndex()]; +- } ++ return ((Mob) this.entity.getHandle()).getEquipmentDropChance(slot); // Paper - use getter on Mob + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java +index f039c5041e783ef55e19194cb7db7610429b1d96..107fa1d4bd977d17dc062da280dda46eb3c5f81c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java +@@ -353,4 +353,15 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i + public void setBootsDropChance(float chance) { + throw new UnsupportedOperationException("Cannot set drop chance for PlayerInventory"); + } ++ // Paper start ++ @Override ++ public float getDropChance(EquipmentSlot slot) { ++ return 1; ++ } ++ ++ @Override ++ public void setDropChance(EquipmentSlot slot, float chance) { ++ throw new UnsupportedOperationException("Cannot set drop chance for PlayerInventory"); ++ } ++ // Paper end + } diff --git a/patches/server/0505-add-get-set-drop-chance-to-EntityEquipment.patch b/patches/server/0505-add-get-set-drop-chance-to-EntityEquipment.patch deleted file mode 100644 index e794470410..0000000000 --- a/patches/server/0505-add-get-set-drop-chance-to-EntityEquipment.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 22 Apr 2021 00:28:11 -0700 -Subject: [PATCH] add get-set drop chance to EntityEquipment - -== AT == -public net.minecraft.world.entity.Mob getEquipmentDropChance(Lnet/minecraft/world/entity/EquipmentSlot;)F - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java -index cb704cef3845727c465fe3ea7210a11545da56c8..fdcc414f4fa246082ad0732133c870d915ae3084 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java -@@ -244,15 +244,22 @@ public class CraftEntityEquipment implements EntityEquipment { - public void setBootsDropChance(float chance) { - this.setDropChance(net.minecraft.world.entity.EquipmentSlot.FEET, chance); - } -+ // Paper start -+ @Override -+ public float getDropChance(EquipmentSlot slot) { -+ return getDropChance(CraftEquipmentSlot.getNMS(slot)); -+ } -+ -+ @Override -+ public void setDropChance(EquipmentSlot slot, float chance) { -+ setDropChance(CraftEquipmentSlot.getNMS(slot), chance); -+ } -+ // Paper end - - private void setDropChance(net.minecraft.world.entity.EquipmentSlot slot, float chance) { - Preconditions.checkArgument(this.entity.getHandle() instanceof Mob, "Cannot set drop chance for non-Mob entity"); - -- if (slot == net.minecraft.world.entity.EquipmentSlot.MAINHAND || slot == net.minecraft.world.entity.EquipmentSlot.OFFHAND) { -- ((Mob) this.entity.getHandle()).handDropChances[slot.getIndex()] = chance; -- } else { -- ((Mob) this.entity.getHandle()).armorDropChances[slot.getIndex()] = chance; -- } -+ ((Mob) this.entity.getHandle()).setDropChance(slot, chance); // Paper - use setter on Mob - } - - private float getDropChance(net.minecraft.world.entity.EquipmentSlot slot) { -@@ -260,10 +267,6 @@ public class CraftEntityEquipment implements EntityEquipment { - return 1; - } - -- if (slot == net.minecraft.world.entity.EquipmentSlot.MAINHAND || slot == net.minecraft.world.entity.EquipmentSlot.OFFHAND) { -- return ((Mob) this.entity.getHandle()).handDropChances[slot.getIndex()]; -- } else { -- return ((Mob) this.entity.getHandle()).armorDropChances[slot.getIndex()]; -- } -+ return ((Mob) this.entity.getHandle()).getEquipmentDropChance(slot); // Paper - use getter on Mob - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java -index f039c5041e783ef55e19194cb7db7610429b1d96..107fa1d4bd977d17dc062da280dda46eb3c5f81c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java -@@ -353,4 +353,15 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i - public void setBootsDropChance(float chance) { - throw new UnsupportedOperationException("Cannot set drop chance for PlayerInventory"); - } -+ // Paper start -+ @Override -+ public float getDropChance(EquipmentSlot slot) { -+ return 1; -+ } -+ -+ @Override -+ public void setDropChance(EquipmentSlot slot, float chance) { -+ throw new UnsupportedOperationException("Cannot set drop chance for PlayerInventory"); -+ } -+ // Paper end - } diff --git a/patches/server/0505-fix-PigZombieAngerEvent-cancellation.patch b/patches/server/0505-fix-PigZombieAngerEvent-cancellation.patch new file mode 100644 index 0000000000..040d076f37 --- /dev/null +++ b/patches/server/0505-fix-PigZombieAngerEvent-cancellation.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Trigary +Date: Thu, 18 Mar 2021 21:38:01 +0100 +Subject: [PATCH] fix PigZombieAngerEvent cancellation + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java +index faaaee79e14adb62e810641ccc8f51428d39883d..03e3cbe73119ca76417d4dd192e1560bdfc373ec 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java +@@ -56,6 +56,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + private static final int ALERT_RANGE_Y = 10; + private static final UniformInt ALERT_INTERVAL = TimeUtil.rangeOfSeconds(4, 6); + private int ticksUntilNextAlert; ++ private HurtByTargetGoal pathfinderGoalHurtByTarget; // Paper - fix PigZombieAngerEvent cancellation + + public ZombifiedPiglin(EntityType type, Level world) { + super(type, world); +@@ -71,7 +72,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + protected void addBehaviourGoals() { + this.goalSelector.addGoal(2, new ZombieAttackGoal(this, 1.0D, false)); + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D)); +- this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers()); ++ this.targetSelector.addGoal(1, pathfinderGoalHurtByTarget = (new HurtByTargetGoal(this, new Class[0])).setAlertOthers()); // Paper - fix PigZombieAngerEvent cancellation + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); + this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true)); + } +@@ -179,6 +180,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + this.level().getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + this.setPersistentAngerTarget(null); ++ pathfinderGoalHurtByTarget.stop(); // Paper - fix PigZombieAngerEvent cancellation + return; + } + this.setRemainingPersistentAngerTime(event.getNewAnger()); diff --git a/patches/server/0506-fix-PigZombieAngerEvent-cancellation.patch b/patches/server/0506-fix-PigZombieAngerEvent-cancellation.patch deleted file mode 100644 index 040d076f37..0000000000 --- a/patches/server/0506-fix-PigZombieAngerEvent-cancellation.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Trigary -Date: Thu, 18 Mar 2021 21:38:01 +0100 -Subject: [PATCH] fix PigZombieAngerEvent cancellation - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -index faaaee79e14adb62e810641ccc8f51428d39883d..03e3cbe73119ca76417d4dd192e1560bdfc373ec 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -@@ -56,6 +56,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - private static final int ALERT_RANGE_Y = 10; - private static final UniformInt ALERT_INTERVAL = TimeUtil.rangeOfSeconds(4, 6); - private int ticksUntilNextAlert; -+ private HurtByTargetGoal pathfinderGoalHurtByTarget; // Paper - fix PigZombieAngerEvent cancellation - - public ZombifiedPiglin(EntityType type, Level world) { - super(type, world); -@@ -71,7 +72,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - protected void addBehaviourGoals() { - this.goalSelector.addGoal(2, new ZombieAttackGoal(this, 1.0D, false)); - this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D)); -- this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers()); -+ this.targetSelector.addGoal(1, pathfinderGoalHurtByTarget = (new HurtByTargetGoal(this, new Class[0])).setAlertOthers()); // Paper - fix PigZombieAngerEvent cancellation - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); - this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true)); - } -@@ -179,6 +180,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - this.level().getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - this.setPersistentAngerTarget(null); -+ pathfinderGoalHurtByTarget.stop(); // Paper - fix PigZombieAngerEvent cancellation - return; - } - this.setRemainingPersistentAngerTime(event.getNewAnger()); diff --git a/patches/server/0506-fix-PlayerItemHeldEvent-firing-twice.patch b/patches/server/0506-fix-PlayerItemHeldEvent-firing-twice.patch new file mode 100644 index 0000000000..7da0534687 --- /dev/null +++ b/patches/server/0506-fix-PlayerItemHeldEvent-firing-twice.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chickeneer +Date: Thu, 22 Apr 2021 19:02:07 -0700 +Subject: [PATCH] fix PlayerItemHeldEvent firing twice + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 7a38ddcfb2ee373e9464f486bf968210ef10dd1a..7864d30a18c76f1170708192e7690cc7b50b15ef 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2014,6 +2014,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (this.player.isImmobile()) return; // CraftBukkit + if (packet.getSlot() >= 0 && packet.getSlot() < Inventory.getSelectionSize()) { ++ if (packet.getSlot() == this.player.getInventory().selected) { return; } // Paper - don't fire itemheldevent when there wasn't a slot change + PlayerItemHeldEvent event = new PlayerItemHeldEvent(this.getCraftPlayer(), this.player.getInventory().selected, packet.getSlot()); + this.cserver.getPluginManager().callEvent(event); + if (event.isCancelled()) { diff --git a/patches/server/0507-Add-PlayerDeepSleepEvent.patch b/patches/server/0507-Add-PlayerDeepSleepEvent.patch new file mode 100644 index 0000000000..1750b3bc37 --- /dev/null +++ b/patches/server/0507-Add-PlayerDeepSleepEvent.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 21 Apr 2021 15:58:19 -0700 +Subject: [PATCH] Add PlayerDeepSleepEvent + + +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 136a6b8e2065c7bada396e0f54f91c841a85c3d8..13f21822d0eb1d167b9b71addb46c4f508301c8d 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -265,6 +265,13 @@ public abstract class Player extends LivingEntity { + + if (this.isSleeping()) { + ++this.sleepCounter; ++ // Paper start - Add PlayerDeepSleepEvent ++ if (this.sleepCounter == SLEEP_DURATION) { ++ if (!new io.papermc.paper.event.player.PlayerDeepSleepEvent((org.bukkit.entity.Player) getBukkitEntity()).callEvent()) { ++ this.sleepCounter = Integer.MIN_VALUE; ++ } ++ } ++ // Paper end - Add PlayerDeepSleepEvent + if (this.sleepCounter > 100) { + this.sleepCounter = 100; + } diff --git a/patches/server/0507-fix-PlayerItemHeldEvent-firing-twice.patch b/patches/server/0507-fix-PlayerItemHeldEvent-firing-twice.patch deleted file mode 100644 index 7da0534687..0000000000 --- a/patches/server/0507-fix-PlayerItemHeldEvent-firing-twice.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: chickeneer -Date: Thu, 22 Apr 2021 19:02:07 -0700 -Subject: [PATCH] fix PlayerItemHeldEvent firing twice - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 7a38ddcfb2ee373e9464f486bf968210ef10dd1a..7864d30a18c76f1170708192e7690cc7b50b15ef 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2014,6 +2014,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); - if (this.player.isImmobile()) return; // CraftBukkit - if (packet.getSlot() >= 0 && packet.getSlot() < Inventory.getSelectionSize()) { -+ if (packet.getSlot() == this.player.getInventory().selected) { return; } // Paper - don't fire itemheldevent when there wasn't a slot change - PlayerItemHeldEvent event = new PlayerItemHeldEvent(this.getCraftPlayer(), this.player.getInventory().selected, packet.getSlot()); - this.cserver.getPluginManager().callEvent(event); - if (event.isCancelled()) { diff --git a/patches/server/0508-Add-PlayerDeepSleepEvent.patch b/patches/server/0508-Add-PlayerDeepSleepEvent.patch deleted file mode 100644 index 1750b3bc37..0000000000 --- a/patches/server/0508-Add-PlayerDeepSleepEvent.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 21 Apr 2021 15:58:19 -0700 -Subject: [PATCH] Add PlayerDeepSleepEvent - - -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 136a6b8e2065c7bada396e0f54f91c841a85c3d8..13f21822d0eb1d167b9b71addb46c4f508301c8d 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -265,6 +265,13 @@ public abstract class Player extends LivingEntity { - - if (this.isSleeping()) { - ++this.sleepCounter; -+ // Paper start - Add PlayerDeepSleepEvent -+ if (this.sleepCounter == SLEEP_DURATION) { -+ if (!new io.papermc.paper.event.player.PlayerDeepSleepEvent((org.bukkit.entity.Player) getBukkitEntity()).callEvent()) { -+ this.sleepCounter = Integer.MIN_VALUE; -+ } -+ } -+ // Paper end - Add PlayerDeepSleepEvent - if (this.sleepCounter > 100) { - this.sleepCounter = 100; - } diff --git a/patches/server/0508-More-World-API.patch b/patches/server/0508-More-World-API.patch new file mode 100644 index 0000000000..2b853eb7b0 --- /dev/null +++ b/patches/server/0508-More-World-API.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 7 Jul 2020 10:52:34 -0700 +Subject: [PATCH] More World API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 69464a4fe467128121fe1a9ba08c9c7154e22c7f..f20717ee4505d28fa44f0f9ced5c71ae75c8a6d9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -2130,6 +2130,28 @@ public class CraftWorld extends CraftRegionAccessor implements World { + return new CraftStructureSearchResult(CraftStructure.minecraftToBukkit(found.getSecond().value()), CraftLocation.toBukkit(found.getFirst(), this)); + } + ++ // Paper start ++ @Override ++ public double getCoordinateScale() { ++ return getHandle().dimensionType().coordinateScale(); ++ } ++ ++ @Override ++ public boolean isFixedTime() { ++ return getHandle().dimensionType().hasFixedTime(); ++ } ++ ++ @Override ++ public Collection getInfiniburn() { ++ return com.google.common.collect.Sets.newHashSet(com.google.common.collect.Iterators.transform(net.minecraft.core.registries.BuiltInRegistries.BLOCK.getTagOrEmpty(this.getHandle().dimensionType().infiniburn()).iterator(), blockHolder -> CraftBlockType.minecraftToBukkit(blockHolder.value()))); ++ } ++ ++ @Override ++ public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) { ++ getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())).orElseThrow(), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position)); ++ } ++ // Paper end ++ + @Override + public BiomeSearchResult locateNearestBiome(Location origin, int radius, Biome... biomes) { + return this.locateNearestBiome(origin, radius, 32, 64, biomes); +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftVector.java b/src/main/java/org/bukkit/craftbukkit/util/CraftVector.java +index 3071ac1ac0e733d73dade49597a39f7d156bbc04..967445b2eb158454100a27369a1f463d69f54f27 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftVector.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftVector.java +@@ -12,4 +12,13 @@ public final class CraftVector { + public static net.minecraft.world.phys.Vec3 toNMS(org.bukkit.util.Vector bukkit) { + return new net.minecraft.world.phys.Vec3(bukkit.getX(), bukkit.getY(), bukkit.getZ()); + } ++ // Paper start ++ public static org.bukkit.util.Vector toBukkit(net.minecraft.core.BlockPos blockPosition) { ++ return new org.bukkit.util.Vector(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); ++ } ++ ++ public static net.minecraft.core.BlockPos toBlockPos(org.bukkit.util.Vector bukkit) { ++ return net.minecraft.core.BlockPos.containing(bukkit.getX(), bukkit.getY(), bukkit.getZ()); ++ } ++ // Paper end + } diff --git a/patches/server/0509-Add-PlayerBedFailEnterEvent.patch b/patches/server/0509-Add-PlayerBedFailEnterEvent.patch new file mode 100644 index 0000000000..375fec28c9 --- /dev/null +++ b/patches/server/0509-Add-PlayerBedFailEnterEvent.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 24 Dec 2020 12:27:41 -0800 +Subject: [PATCH] Add PlayerBedFailEnterEvent + + +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 1e5f1b4c746fe9a105c2771c785976aae70a9a3e..30db6ae29e2fe03866dfa656330f7341e0a3f9ab 100644 +--- a/src/main/java/net/minecraft/world/level/block/BedBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java +@@ -120,14 +120,23 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock + BlockPos finalblockposition = pos; + // CraftBukkit end + player.startSleepInBed(pos).ifLeft((entityhuman_enumbedresult) -> { ++ // Paper start - PlayerBedFailEnterEvent ++ if (entityhuman_enumbedresult != null) { ++ io.papermc.paper.event.player.PlayerBedFailEnterEvent event = new io.papermc.paper.event.player.PlayerBedFailEnterEvent((org.bukkit.entity.Player) player.getBukkitEntity(), io.papermc.paper.event.player.PlayerBedFailEnterEvent.FailReason.values()[entityhuman_enumbedresult.ordinal()], org.bukkit.craftbukkit.block.CraftBlock.at(world, finalblockposition), !world.dimensionType().bedWorks(), io.papermc.paper.adventure.PaperAdventure.asAdventure(entityhuman_enumbedresult.getMessage())); ++ if (!event.callEvent()) { ++ return; ++ } ++ // Paper end - PlayerBedFailEnterEvent + // CraftBukkit start - handling bed explosion from below here +- if (!world.dimensionType().bedWorks()) { ++ if (event.getWillExplode()) { // Paper - PlayerBedFailEnterEvent + this.explodeBed(finaliblockdata, world, finalblockposition); + } else + // CraftBukkit end + if (entityhuman_enumbedresult.getMessage() != null) { +- player.displayClientMessage(entityhuman_enumbedresult.getMessage(), true); ++ final net.kyori.adventure.text.Component message = event.getMessage(); // Paper - PlayerBedFailEnterEvent ++ if (message != null) player.displayClientMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), true); // Paper - PlayerBedFailEnterEvent + } ++ } // Paper - PlayerBedFailEnterEvent + + }); + return InteractionResult.SUCCESS_SERVER; diff --git a/patches/server/0509-More-World-API.patch b/patches/server/0509-More-World-API.patch deleted file mode 100644 index 2b853eb7b0..0000000000 --- a/patches/server/0509-More-World-API.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 7 Jul 2020 10:52:34 -0700 -Subject: [PATCH] More World API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 69464a4fe467128121fe1a9ba08c9c7154e22c7f..f20717ee4505d28fa44f0f9ced5c71ae75c8a6d9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2130,6 +2130,28 @@ public class CraftWorld extends CraftRegionAccessor implements World { - return new CraftStructureSearchResult(CraftStructure.minecraftToBukkit(found.getSecond().value()), CraftLocation.toBukkit(found.getFirst(), this)); - } - -+ // Paper start -+ @Override -+ public double getCoordinateScale() { -+ return getHandle().dimensionType().coordinateScale(); -+ } -+ -+ @Override -+ public boolean isFixedTime() { -+ return getHandle().dimensionType().hasFixedTime(); -+ } -+ -+ @Override -+ public Collection getInfiniburn() { -+ return com.google.common.collect.Sets.newHashSet(com.google.common.collect.Iterators.transform(net.minecraft.core.registries.BuiltInRegistries.BLOCK.getTagOrEmpty(this.getHandle().dimensionType().infiniburn()).iterator(), blockHolder -> CraftBlockType.minecraftToBukkit(blockHolder.value()))); -+ } -+ -+ @Override -+ public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) { -+ getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())).orElseThrow(), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position)); -+ } -+ // Paper end -+ - @Override - public BiomeSearchResult locateNearestBiome(Location origin, int radius, Biome... biomes) { - return this.locateNearestBiome(origin, radius, 32, 64, biomes); -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftVector.java b/src/main/java/org/bukkit/craftbukkit/util/CraftVector.java -index 3071ac1ac0e733d73dade49597a39f7d156bbc04..967445b2eb158454100a27369a1f463d69f54f27 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftVector.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftVector.java -@@ -12,4 +12,13 @@ public final class CraftVector { - public static net.minecraft.world.phys.Vec3 toNMS(org.bukkit.util.Vector bukkit) { - return new net.minecraft.world.phys.Vec3(bukkit.getX(), bukkit.getY(), bukkit.getZ()); - } -+ // Paper start -+ public static org.bukkit.util.Vector toBukkit(net.minecraft.core.BlockPos blockPosition) { -+ return new org.bukkit.util.Vector(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); -+ } -+ -+ public static net.minecraft.core.BlockPos toBlockPos(org.bukkit.util.Vector bukkit) { -+ return net.minecraft.core.BlockPos.containing(bukkit.getX(), bukkit.getY(), bukkit.getZ()); -+ } -+ // Paper end - } diff --git a/patches/server/0510-Add-PlayerBedFailEnterEvent.patch b/patches/server/0510-Add-PlayerBedFailEnterEvent.patch deleted file mode 100644 index 375fec28c9..0000000000 --- a/patches/server/0510-Add-PlayerBedFailEnterEvent.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 24 Dec 2020 12:27:41 -0800 -Subject: [PATCH] Add PlayerBedFailEnterEvent - - -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 1e5f1b4c746fe9a105c2771c785976aae70a9a3e..30db6ae29e2fe03866dfa656330f7341e0a3f9ab 100644 ---- a/src/main/java/net/minecraft/world/level/block/BedBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java -@@ -120,14 +120,23 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock - BlockPos finalblockposition = pos; - // CraftBukkit end - player.startSleepInBed(pos).ifLeft((entityhuman_enumbedresult) -> { -+ // Paper start - PlayerBedFailEnterEvent -+ if (entityhuman_enumbedresult != null) { -+ io.papermc.paper.event.player.PlayerBedFailEnterEvent event = new io.papermc.paper.event.player.PlayerBedFailEnterEvent((org.bukkit.entity.Player) player.getBukkitEntity(), io.papermc.paper.event.player.PlayerBedFailEnterEvent.FailReason.values()[entityhuman_enumbedresult.ordinal()], org.bukkit.craftbukkit.block.CraftBlock.at(world, finalblockposition), !world.dimensionType().bedWorks(), io.papermc.paper.adventure.PaperAdventure.asAdventure(entityhuman_enumbedresult.getMessage())); -+ if (!event.callEvent()) { -+ return; -+ } -+ // Paper end - PlayerBedFailEnterEvent - // CraftBukkit start - handling bed explosion from below here -- if (!world.dimensionType().bedWorks()) { -+ if (event.getWillExplode()) { // Paper - PlayerBedFailEnterEvent - this.explodeBed(finaliblockdata, world, finalblockposition); - } else - // CraftBukkit end - if (entityhuman_enumbedresult.getMessage() != null) { -- player.displayClientMessage(entityhuman_enumbedresult.getMessage(), true); -+ final net.kyori.adventure.text.Component message = event.getMessage(); // Paper - PlayerBedFailEnterEvent -+ if (message != null) player.displayClientMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), true); // Paper - PlayerBedFailEnterEvent - } -+ } // Paper - PlayerBedFailEnterEvent - - }); - return InteractionResult.SUCCESS_SERVER; diff --git a/patches/server/0510-Implement-methods-to-convert-between-Component-and-B.patch b/patches/server/0510-Implement-methods-to-convert-between-Component-and-B.patch new file mode 100644 index 0000000000..c5765e9de7 --- /dev/null +++ b/patches/server/0510-Implement-methods-to-convert-between-Component-and-B.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Sat, 24 Apr 2021 02:09:32 -0700 +Subject: [PATCH] Implement methods to convert between Component and + Brigadier's Message + + +diff --git a/src/main/java/io/papermc/paper/brigadier/PaperBrigadierProviderImpl.java b/src/main/java/io/papermc/paper/brigadier/PaperBrigadierProviderImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..dd6012b6a097575b2d1471be5069eccee4537c0a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/brigadier/PaperBrigadierProviderImpl.java +@@ -0,0 +1,30 @@ ++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/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 7c92b2f0a59fe222ad13a998476e312bf571a1bf..761663514b98a1c0a0a905150411aff450a0cc50 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -224,6 +224,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command + com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics + com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now ++ io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // Paper - init PaperBrigadierProvider + + this.setPvpAllowed(dedicatedserverproperties.pvp); + this.setFlightAllowed(dedicatedserverproperties.allowFlight); diff --git a/patches/server/0511-Expand-PlayerRespawnEvent-fix-passed-parameter-issue.patch b/patches/server/0511-Expand-PlayerRespawnEvent-fix-passed-parameter-issue.patch new file mode 100644 index 0000000000..3013063e3f --- /dev/null +++ b/patches/server/0511-Expand-PlayerRespawnEvent-fix-passed-parameter-issue.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: HexedHero <6012891+HexedHero@users.noreply.github.com> +Date: Fri, 23 Apr 2021 22:42:42 +0100 +Subject: [PATCH] Expand PlayerRespawnEvent, fix passed parameter issues + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 82921c10beee7c37994881618c508fc3a14834eb..0e4fe0a2a160c4965cdbfe3d6d375a66c129894d 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1447,7 +1447,13 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + Player respawnPlayer = this.getBukkitEntity(); + Location location = CraftLocation.toBukkit(teleportTransition.position(), teleportTransition.newLevel().getWorld(), teleportTransition.yRot(), teleportTransition.xRot()); + +- PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(respawnPlayer, location, isBedSpawn, isAnchorSpawn, reason); ++ // Paper start - respawn flags ++ com.google.common.collect.ImmutableSet.Builder builder = com.google.common.collect.ImmutableSet.builder(); ++ if (reason == org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.END_PORTAL) { ++ builder.add(org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag.END_PORTAL); ++ } ++ PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(respawnPlayer, location, isBedSpawn, isAnchorSpawn, reason, builder); ++ // Paper end - respawn flags + this.level().getCraftServer().getPluginManager().callEvent(respawnEvent); + // Spigot Start + if (this.connection.isDisconnected()) { diff --git a/patches/server/0511-Implement-methods-to-convert-between-Component-and-B.patch b/patches/server/0511-Implement-methods-to-convert-between-Component-and-B.patch deleted file mode 100644 index c5765e9de7..0000000000 --- a/patches/server/0511-Implement-methods-to-convert-between-Component-and-B.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sat, 24 Apr 2021 02:09:32 -0700 -Subject: [PATCH] Implement methods to convert between Component and - Brigadier's Message - - -diff --git a/src/main/java/io/papermc/paper/brigadier/PaperBrigadierProviderImpl.java b/src/main/java/io/papermc/paper/brigadier/PaperBrigadierProviderImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..dd6012b6a097575b2d1471be5069eccee4537c0a ---- /dev/null -+++ b/src/main/java/io/papermc/paper/brigadier/PaperBrigadierProviderImpl.java -@@ -0,0 +1,30 @@ -+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/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 7c92b2f0a59fe222ad13a998476e312bf571a1bf..761663514b98a1c0a0a905150411aff450a0cc50 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -224,6 +224,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command - com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics - com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now -+ io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // Paper - init PaperBrigadierProvider - - this.setPvpAllowed(dedicatedserverproperties.pvp); - this.setFlightAllowed(dedicatedserverproperties.allowFlight); diff --git a/patches/server/0512-Expand-PlayerRespawnEvent-fix-passed-parameter-issue.patch b/patches/server/0512-Expand-PlayerRespawnEvent-fix-passed-parameter-issue.patch deleted file mode 100644 index 017cc4e93e..0000000000 --- a/patches/server/0512-Expand-PlayerRespawnEvent-fix-passed-parameter-issue.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: HexedHero <6012891+HexedHero@users.noreply.github.com> -Date: Fri, 23 Apr 2021 22:42:42 +0100 -Subject: [PATCH] Expand PlayerRespawnEvent, fix passed parameter issues - -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index f046b8e6307079878d94eab615a5463a807e6c6c..c22dce8b30c8af3e37b497b0d97c6ceef0295883 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1447,7 +1447,13 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - Player respawnPlayer = this.getBukkitEntity(); - Location location = CraftLocation.toBukkit(teleportTransition.position(), teleportTransition.newLevel().getWorld(), teleportTransition.yRot(), teleportTransition.xRot()); - -- PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(respawnPlayer, location, isBedSpawn, isAnchorSpawn, reason); -+ // Paper start - respawn flags -+ com.google.common.collect.ImmutableSet.Builder builder = com.google.common.collect.ImmutableSet.builder(); -+ if (reason == org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.END_PORTAL) { -+ builder.add(org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag.END_PORTAL); -+ } -+ PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(respawnPlayer, location, isBedSpawn, isAnchorSpawn, reason, builder); -+ // Paper end - respawn flags - this.level().getCraftServer().getPluginManager().callEvent(respawnEvent); - // Spigot Start - if (this.connection.isDisconnected()) { diff --git a/patches/server/0512-Introduce-beacon-activation-deactivation-events.patch b/patches/server/0512-Introduce-beacon-activation-deactivation-events.patch new file mode 100644 index 0000000000..336acbe811 --- /dev/null +++ b/patches/server/0512-Introduce-beacon-activation-deactivation-events.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spyridon Pagkalos +Date: Thu, 25 Mar 2021 20:28:04 +0200 +Subject: [PATCH] Introduce beacon activation/deactivation events + + +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 dc3171b1493d7c4c8ddf1c79587c4e27bd819c17..8aab6f68f576fb022eb59798585e264f5aafbc69 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 +@@ -225,6 +225,15 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + BeaconBlockEntity.playSound(world, pos, SoundEvents.BEACON_AMBIENT); + } + } ++ // Paper start - beacon activation/deactivation events ++ if (i1 <= 0 && blockEntity.levels > 0) { ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos); ++ new io.papermc.paper.event.block.BeaconActivatedEvent(block).callEvent(); ++ } else if (i1 > 0 && blockEntity.levels <= 0) { ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos); ++ new io.papermc.paper.event.block.BeaconDeactivatedEvent(block).callEvent(); ++ } ++ // Paper end - beacon activation/deactivation events + + if (blockEntity.lastCheckY >= l) { + blockEntity.lastCheckY = world.getMinY() - 1; +@@ -282,6 +291,10 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + + @Override + public void setRemoved() { ++ // Paper start - beacon activation/deactivation events ++ 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 + BeaconBlockEntity.playSound(this.level, this.worldPosition, SoundEvents.BEACON_DEACTIVATE); + super.setRemoved(); + } diff --git a/patches/server/0513-Add-Channel-initialization-listeners.patch b/patches/server/0513-Add-Channel-initialization-listeners.patch new file mode 100644 index 0000000000..430324c8f2 --- /dev/null +++ b/patches/server/0513-Add-Channel-initialization-listeners.patch @@ -0,0 +1,155 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Thu, 29 Apr 2021 21:19:33 +0200 +Subject: [PATCH] Add Channel initialization listeners + + +diff --git a/src/main/java/io/papermc/paper/network/ChannelInitializeListener.java b/src/main/java/io/papermc/paper/network/ChannelInitializeListener.java +new file mode 100644 +index 0000000000000000000000000000000000000000..88099df34c2d74daba9645aadf65b446ca795a91 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/network/ChannelInitializeListener.java +@@ -0,0 +1,15 @@ ++package io.papermc.paper.network; ++ ++import io.netty.channel.Channel; ++import org.checkerframework.checker.nullness.qual.NonNull; ++ ++/** ++ * Internal API to register channel initialization listeners. ++ *

++ * This is not officially supported API and we make no guarantees to the existence or state of this interface. ++ */ ++@FunctionalInterface ++public interface ChannelInitializeListener { ++ ++ void afterInitChannel(@NonNull Channel channel); ++} +diff --git a/src/main/java/io/papermc/paper/network/ChannelInitializeListenerHolder.java b/src/main/java/io/papermc/paper/network/ChannelInitializeListenerHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..30e62719e0a83525daa33cf41cb61df360c0e046 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/network/ChannelInitializeListenerHolder.java +@@ -0,0 +1,74 @@ ++package io.papermc.paper.network; ++ ++import io.netty.channel.Channel; ++import net.kyori.adventure.key.Key; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++import java.util.Collections; ++import java.util.HashMap; ++import java.util.Map; ++ ++/** ++ * Internal API to register channel initialization listeners. ++ *

++ * This is not officially supported API and we make no guarantees to the existence or state of this class. ++ */ ++public final class ChannelInitializeListenerHolder { ++ ++ private static final Map LISTENERS = new HashMap<>(); ++ private static final Map IMMUTABLE_VIEW = Collections.unmodifiableMap(LISTENERS); ++ ++ private ChannelInitializeListenerHolder() { ++ } ++ ++ /** ++ * Registers whether an initialization listener is registered under the given key. ++ * ++ * @param key key ++ * @return whether an initialization listener is registered under the given key ++ */ ++ public static boolean hasListener(@NonNull Key key) { ++ return LISTENERS.containsKey(key); ++ } ++ ++ /** ++ * Registers a channel initialization listener called after ServerConnection is initialized. ++ * ++ * @param key key ++ * @param listener initialization listeners ++ */ ++ public static void addListener(@NonNull Key key, @NonNull ChannelInitializeListener listener) { ++ LISTENERS.put(key, listener); ++ } ++ ++ /** ++ * Removes and returns an initialization listener registered by the given key if present. ++ * ++ * @param key key ++ * @return removed initialization listener if present ++ */ ++ public static @Nullable ChannelInitializeListener removeListener(@NonNull Key key) { ++ return LISTENERS.remove(key); ++ } ++ ++ /** ++ * Returns an immutable map of registered initialization listeners. ++ * ++ * @return immutable map of registered initialization listeners ++ */ ++ public static @NonNull Map getListeners() { ++ return IMMUTABLE_VIEW; ++ } ++ ++ /** ++ * Calls the registered listeners with the given channel. ++ * ++ * @param channel channel ++ */ ++ public static void callListeners(@NonNull Channel channel) { ++ for (ChannelInitializeListener listener : LISTENERS.values()) { ++ listener.afterInitChannel(channel); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/network/ConnectionEvent.java b/src/main/java/io/papermc/paper/network/ConnectionEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0d7e7db9e37ef0183c32b217bd944fb4f41ab83a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/network/ConnectionEvent.java +@@ -0,0 +1,10 @@ ++package io.papermc.paper.network; ++ ++/** ++ * Internal connection pipeline events. ++ */ ++public enum ConnectionEvent { ++ ++ COMPRESSION_THRESHOLD_SET, ++ COMPRESSION_DISABLED ++} +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index 448bde861b4190a678a8ccb63cade43c4a3d6ad9..f5fe87103ce53ba07b43c6c10fc9dafcc5ea4958 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -680,6 +680,7 @@ public class Connection extends SimpleChannelInboundHandler> { + } else { + this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressionThreshold)); + } ++ this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners + } else { + if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) { + this.channel.pipeline().remove("decompress"); +@@ -688,6 +689,7 @@ public class Connection extends SimpleChannelInboundHandler> { + if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) { + this.channel.pipeline().remove("compress"); + } ++ this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_DISABLED); // Paper - Add Channel initialization listeners + } + + } +diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +index 64119f2188f8958b8a5913fec82ac5bba1b74b2a..d6d7f1c446ba5507f67038ff27775ba75156f4a7 100644 +--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java ++++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +@@ -115,6 +115,7 @@ public class ServerConnectionListener { + 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)); ++ io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper - Add Channel initialization listeners + } + }).group(eventloopgroup).localAddress(address, port)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit + } diff --git a/patches/server/0513-Introduce-beacon-activation-deactivation-events.patch b/patches/server/0513-Introduce-beacon-activation-deactivation-events.patch deleted file mode 100644 index 336acbe811..0000000000 --- a/patches/server/0513-Introduce-beacon-activation-deactivation-events.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spyridon Pagkalos -Date: Thu, 25 Mar 2021 20:28:04 +0200 -Subject: [PATCH] Introduce beacon activation/deactivation events - - -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 dc3171b1493d7c4c8ddf1c79587c4e27bd819c17..8aab6f68f576fb022eb59798585e264f5aafbc69 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 -@@ -225,6 +225,15 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - BeaconBlockEntity.playSound(world, pos, SoundEvents.BEACON_AMBIENT); - } - } -+ // Paper start - beacon activation/deactivation events -+ if (i1 <= 0 && blockEntity.levels > 0) { -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos); -+ new io.papermc.paper.event.block.BeaconActivatedEvent(block).callEvent(); -+ } else if (i1 > 0 && blockEntity.levels <= 0) { -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, pos); -+ new io.papermc.paper.event.block.BeaconDeactivatedEvent(block).callEvent(); -+ } -+ // Paper end - beacon activation/deactivation events - - if (blockEntity.lastCheckY >= l) { - blockEntity.lastCheckY = world.getMinY() - 1; -@@ -282,6 +291,10 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - - @Override - public void setRemoved() { -+ // Paper start - beacon activation/deactivation events -+ 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 - BeaconBlockEntity.playSound(this.level, this.worldPosition, SoundEvents.BEACON_DEACTIVATE); - super.setRemoved(); - } diff --git a/patches/server/0514-Add-Channel-initialization-listeners.patch b/patches/server/0514-Add-Channel-initialization-listeners.patch deleted file mode 100644 index 430324c8f2..0000000000 --- a/patches/server/0514-Add-Channel-initialization-listeners.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Thu, 29 Apr 2021 21:19:33 +0200 -Subject: [PATCH] Add Channel initialization listeners - - -diff --git a/src/main/java/io/papermc/paper/network/ChannelInitializeListener.java b/src/main/java/io/papermc/paper/network/ChannelInitializeListener.java -new file mode 100644 -index 0000000000000000000000000000000000000000..88099df34c2d74daba9645aadf65b446ca795a91 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/network/ChannelInitializeListener.java -@@ -0,0 +1,15 @@ -+package io.papermc.paper.network; -+ -+import io.netty.channel.Channel; -+import org.checkerframework.checker.nullness.qual.NonNull; -+ -+/** -+ * Internal API to register channel initialization listeners. -+ *

-+ * This is not officially supported API and we make no guarantees to the existence or state of this interface. -+ */ -+@FunctionalInterface -+public interface ChannelInitializeListener { -+ -+ void afterInitChannel(@NonNull Channel channel); -+} -diff --git a/src/main/java/io/papermc/paper/network/ChannelInitializeListenerHolder.java b/src/main/java/io/papermc/paper/network/ChannelInitializeListenerHolder.java -new file mode 100644 -index 0000000000000000000000000000000000000000..30e62719e0a83525daa33cf41cb61df360c0e046 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/network/ChannelInitializeListenerHolder.java -@@ -0,0 +1,74 @@ -+package io.papermc.paper.network; -+ -+import io.netty.channel.Channel; -+import net.kyori.adventure.key.Key; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+ -+import java.util.Collections; -+import java.util.HashMap; -+import java.util.Map; -+ -+/** -+ * Internal API to register channel initialization listeners. -+ *

-+ * This is not officially supported API and we make no guarantees to the existence or state of this class. -+ */ -+public final class ChannelInitializeListenerHolder { -+ -+ private static final Map LISTENERS = new HashMap<>(); -+ private static final Map IMMUTABLE_VIEW = Collections.unmodifiableMap(LISTENERS); -+ -+ private ChannelInitializeListenerHolder() { -+ } -+ -+ /** -+ * Registers whether an initialization listener is registered under the given key. -+ * -+ * @param key key -+ * @return whether an initialization listener is registered under the given key -+ */ -+ public static boolean hasListener(@NonNull Key key) { -+ return LISTENERS.containsKey(key); -+ } -+ -+ /** -+ * Registers a channel initialization listener called after ServerConnection is initialized. -+ * -+ * @param key key -+ * @param listener initialization listeners -+ */ -+ public static void addListener(@NonNull Key key, @NonNull ChannelInitializeListener listener) { -+ LISTENERS.put(key, listener); -+ } -+ -+ /** -+ * Removes and returns an initialization listener registered by the given key if present. -+ * -+ * @param key key -+ * @return removed initialization listener if present -+ */ -+ public static @Nullable ChannelInitializeListener removeListener(@NonNull Key key) { -+ return LISTENERS.remove(key); -+ } -+ -+ /** -+ * Returns an immutable map of registered initialization listeners. -+ * -+ * @return immutable map of registered initialization listeners -+ */ -+ public static @NonNull Map getListeners() { -+ return IMMUTABLE_VIEW; -+ } -+ -+ /** -+ * Calls the registered listeners with the given channel. -+ * -+ * @param channel channel -+ */ -+ public static void callListeners(@NonNull Channel channel) { -+ for (ChannelInitializeListener listener : LISTENERS.values()) { -+ listener.afterInitChannel(channel); -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/network/ConnectionEvent.java b/src/main/java/io/papermc/paper/network/ConnectionEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0d7e7db9e37ef0183c32b217bd944fb4f41ab83a ---- /dev/null -+++ b/src/main/java/io/papermc/paper/network/ConnectionEvent.java -@@ -0,0 +1,10 @@ -+package io.papermc.paper.network; -+ -+/** -+ * Internal connection pipeline events. -+ */ -+public enum ConnectionEvent { -+ -+ COMPRESSION_THRESHOLD_SET, -+ COMPRESSION_DISABLED -+} -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index 448bde861b4190a678a8ccb63cade43c4a3d6ad9..f5fe87103ce53ba07b43c6c10fc9dafcc5ea4958 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -680,6 +680,7 @@ public class Connection extends SimpleChannelInboundHandler> { - } else { - this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressionThreshold)); - } -+ this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners - } else { - if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) { - this.channel.pipeline().remove("decompress"); -@@ -688,6 +689,7 @@ public class Connection extends SimpleChannelInboundHandler> { - if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) { - this.channel.pipeline().remove("compress"); - } -+ this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_DISABLED); // Paper - Add Channel initialization listeners - } - - } -diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index 64119f2188f8958b8a5913fec82ac5bba1b74b2a..d6d7f1c446ba5507f67038ff27775ba75156f4a7 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -115,6 +115,7 @@ public class ServerConnectionListener { - 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)); -+ io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper - Add Channel initialization listeners - } - }).group(eventloopgroup).localAddress(address, port)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit - } diff --git a/patches/server/0514-Send-empty-commands-if-tab-completion-is-disabled.patch b/patches/server/0514-Send-empty-commands-if-tab-completion-is-disabled.patch new file mode 100644 index 0000000000..35cf408aa7 --- /dev/null +++ b/patches/server/0514-Send-empty-commands-if-tab-completion-is-disabled.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder +Date: Mon, 26 Apr 2021 01:27:08 +0100 +Subject: [PATCH] Send empty commands if tab completion is disabled + + +diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java +index 2dcb1a1bdba1d1cad3caa117d85a8619ed9e67b4..d602c713696e23ba6a2d542b2e9e2cce46d79a66 100644 +--- a/src/main/java/net/minecraft/commands/Commands.java ++++ b/src/main/java/net/minecraft/commands/Commands.java +@@ -453,7 +453,12 @@ public class Commands { + } + + public void sendCommands(ServerPlayer player) { +- if ( org.spigotmc.SpigotConfig.tabComplete < 0 ) return; // Spigot ++ // Paper start - Send empty commands if tab completion is disabled ++ if (org.spigotmc.SpigotConfig.tabComplete < 0) { ++ player.connection.send(new ClientboundCommandsPacket(new RootCommandNode<>())); ++ return; ++ } ++ // Paper end - Send empty commands if tab completion is disabled + // CraftBukkit start + // Register Vanilla commands into builtRoot as before + // Paper start - Perf: Async command map building diff --git a/patches/server/0515-Add-more-WanderingTrader-API.patch b/patches/server/0515-Add-more-WanderingTrader-API.patch new file mode 100644 index 0000000000..4221f28015 --- /dev/null +++ b/patches/server/0515-Add-more-WanderingTrader-API.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: HexedHero <6012891+HexedHero@users.noreply.github.com> +Date: Thu, 6 May 2021 14:56:43 +0100 +Subject: [PATCH] Add more WanderingTrader API + + +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 8034588a9a87b907c35e28e220280d463f34554e..a65fba5621c067c453858efb7fee64cbee1e7916 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java ++++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java +@@ -62,6 +62,10 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + @Nullable + private BlockPos wanderTarget; + private int despawnDelay; ++ // Paper start - Add more WanderingTrader API ++ public boolean canDrinkPotion = true; ++ public boolean canDrinkMilk = true; ++ // Paper end - Add more WanderingTrader API + + public WanderingTrader(EntityType type, Level world) { + super(type, world); +@@ -72,10 +76,10 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new UseItemGoal<>(this, PotionContents.createItemStack(Items.POTION, Potions.INVISIBILITY), SoundEvents.WANDERING_TRADER_DISAPPEARED, (entityvillagertrader) -> { +- return this.level().isNight() && !entityvillagertrader.isInvisible(); ++ return this.canDrinkPotion && this.level().isNight() && !entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API + })); + this.goalSelector.addGoal(0, new UseItemGoal<>(this, new ItemStack(Items.MILK_BUCKET), SoundEvents.WANDERING_TRADER_REAPPEARED, (entityvillagertrader) -> { +- return this.level().isDay() && entityvillagertrader.isInvisible(); ++ return this.canDrinkMilk && this.level().isDay() && entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API + })); + this.goalSelector.addGoal(1, new TradeWithPlayerGoal(this)); + this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Zombie.class, 8.0F, 0.5D, 0.5D)); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java +index 08194a78c2170e971ee8ff440b276ed3590e8c4a..0e597394a3dd08f022614fc9777302fea581eb55 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java +@@ -28,4 +28,26 @@ public class CraftWanderingTrader extends CraftAbstractVillager implements Wande + public void setDespawnDelay(int despawnDelay) { + this.getHandle().setDespawnDelay(despawnDelay); + } ++ ++ // Paper start - Add more WanderingTrader API ++ @Override ++ public void setCanDrinkPotion(boolean bool) { ++ getHandle().canDrinkPotion = bool; ++ } ++ ++ @Override ++ public boolean canDrinkPotion() { ++ return getHandle().canDrinkPotion; ++ } ++ ++ @Override ++ public void setCanDrinkMilk(boolean bool) { ++ getHandle().canDrinkMilk = bool; ++ } ++ ++ @Override ++ public boolean canDrinkMilk() { ++ return getHandle().canDrinkMilk; ++ } ++ // Paper end + } diff --git a/patches/server/0515-Send-empty-commands-if-tab-completion-is-disabled.patch b/patches/server/0515-Send-empty-commands-if-tab-completion-is-disabled.patch deleted file mode 100644 index 35cf408aa7..0000000000 --- a/patches/server/0515-Send-empty-commands-if-tab-completion-is-disabled.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder -Date: Mon, 26 Apr 2021 01:27:08 +0100 -Subject: [PATCH] Send empty commands if tab completion is disabled - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 2dcb1a1bdba1d1cad3caa117d85a8619ed9e67b4..d602c713696e23ba6a2d542b2e9e2cce46d79a66 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -453,7 +453,12 @@ public class Commands { - } - - public void sendCommands(ServerPlayer player) { -- if ( org.spigotmc.SpigotConfig.tabComplete < 0 ) return; // Spigot -+ // Paper start - Send empty commands if tab completion is disabled -+ if (org.spigotmc.SpigotConfig.tabComplete < 0) { -+ player.connection.send(new ClientboundCommandsPacket(new RootCommandNode<>())); -+ return; -+ } -+ // Paper end - Send empty commands if tab completion is disabled - // CraftBukkit start - // Register Vanilla commands into builtRoot as before - // Paper start - Perf: Async command map building diff --git a/patches/server/0516-Add-EntityBlockStorage-clearEntities.patch b/patches/server/0516-Add-EntityBlockStorage-clearEntities.patch new file mode 100644 index 0000000000..51ffd96ff7 --- /dev/null +++ b/patches/server/0516-Add-EntityBlockStorage-clearEntities.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Mon, 5 Apr 2021 18:12:29 -0400 +Subject: [PATCH] Add EntityBlockStorage#clearEntities() + + +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 333189cf01ce571993e8152f5851b8c362ba4b70..801528022c902714138c264bc4d05ef0df85912e 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 +@@ -152,6 +152,11 @@ public class BeehiveBlockEntity extends BlockEntity { + return this.stored.size(); + } + ++ // Paper start - Add EntityBlockStorage clearEntities ++ public void clearBees() { ++ this.stored.clear(); ++ } ++ // Paper end - Add EntityBlockStorage clearEntities + public static int getHoneyLevel(BlockState state) { + return (Integer) state.getValue(BeehiveBlock.HONEY_LEVEL); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java +index fbacbef0dd51037fa0af56fedeea50a5c7bed8c7..1a2a05160ba51d9c75f1ae6ae61d944d81428722 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java +@@ -95,4 +95,11 @@ public class CraftBeehive extends CraftBlockEntityState impl + public CraftBeehive copy(Location location) { + return new CraftBeehive(this, location); + } ++ ++ // Paper start - Add EntityBlockStorage clearEntities ++ @Override ++ public void clearEntities() { ++ getSnapshot().clearBees(); ++ } ++ // Paper end + } diff --git a/patches/server/0516-Add-more-WanderingTrader-API.patch b/patches/server/0516-Add-more-WanderingTrader-API.patch deleted file mode 100644 index 4221f28015..0000000000 --- a/patches/server/0516-Add-more-WanderingTrader-API.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: HexedHero <6012891+HexedHero@users.noreply.github.com> -Date: Thu, 6 May 2021 14:56:43 +0100 -Subject: [PATCH] Add more WanderingTrader API - - -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 8034588a9a87b907c35e28e220280d463f34554e..a65fba5621c067c453858efb7fee64cbee1e7916 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -62,6 +62,10 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - @Nullable - private BlockPos wanderTarget; - private int despawnDelay; -+ // Paper start - Add more WanderingTrader API -+ public boolean canDrinkPotion = true; -+ public boolean canDrinkMilk = true; -+ // Paper end - Add more WanderingTrader API - - public WanderingTrader(EntityType type, Level world) { - super(type, world); -@@ -72,10 +76,10 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); - this.goalSelector.addGoal(0, new UseItemGoal<>(this, PotionContents.createItemStack(Items.POTION, Potions.INVISIBILITY), SoundEvents.WANDERING_TRADER_DISAPPEARED, (entityvillagertrader) -> { -- return this.level().isNight() && !entityvillagertrader.isInvisible(); -+ return this.canDrinkPotion && this.level().isNight() && !entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API - })); - this.goalSelector.addGoal(0, new UseItemGoal<>(this, new ItemStack(Items.MILK_BUCKET), SoundEvents.WANDERING_TRADER_REAPPEARED, (entityvillagertrader) -> { -- return this.level().isDay() && entityvillagertrader.isInvisible(); -+ return this.canDrinkMilk && this.level().isDay() && entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API - })); - this.goalSelector.addGoal(1, new TradeWithPlayerGoal(this)); - this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Zombie.class, 8.0F, 0.5D, 0.5D)); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java -index 08194a78c2170e971ee8ff440b276ed3590e8c4a..0e597394a3dd08f022614fc9777302fea581eb55 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java -@@ -28,4 +28,26 @@ public class CraftWanderingTrader extends CraftAbstractVillager implements Wande - public void setDespawnDelay(int despawnDelay) { - this.getHandle().setDespawnDelay(despawnDelay); - } -+ -+ // Paper start - Add more WanderingTrader API -+ @Override -+ public void setCanDrinkPotion(boolean bool) { -+ getHandle().canDrinkPotion = bool; -+ } -+ -+ @Override -+ public boolean canDrinkPotion() { -+ return getHandle().canDrinkPotion; -+ } -+ -+ @Override -+ public void setCanDrinkMilk(boolean bool) { -+ getHandle().canDrinkMilk = bool; -+ } -+ -+ @Override -+ public boolean canDrinkMilk() { -+ return getHandle().canDrinkMilk; -+ } -+ // Paper end - } diff --git a/patches/server/0517-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch b/patches/server/0517-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch new file mode 100644 index 0000000000..9df7276feb --- /dev/null +++ b/patches/server/0517-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alvinn8 <42838560+Alvinn8@users.noreply.github.com> +Date: Fri, 8 Jan 2021 20:31:13 +0100 +Subject: [PATCH] Add Adventure message to PlayerAdvancementDoneEvent + + +diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java +index 0fe941b0802f2966ad55509baac124f56ecef999..1dcb8a287be7df2a59b5b4c1345be80637a7f679 100644 +--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java ++++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java +@@ -236,11 +236,21 @@ public class PlayerAdvancements { + this.progressChanged.add(advancement); + flag = true; + if (!flag1 && advancementprogress.isDone()) { +- this.player.level().getCraftServer().getPluginManager().callEvent(new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancement.toBukkit())); // CraftBukkit ++ // Paper start - Add Adventure message to PlayerAdvancementDoneEvent ++ final net.kyori.adventure.text.Component message = advancement.value().display().flatMap(info -> { ++ return java.util.Optional.ofNullable( ++ info.shouldAnnounceChat() ? io.papermc.paper.adventure.PaperAdventure.asAdventure(info.getType().createAnnouncement(advancement, this.player)) : null ++ ); ++ }).orElse(null); ++ final org.bukkit.event.player.PlayerAdvancementDoneEvent event = new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancement.toBukkit(), message); ++ this.player.level().getCraftServer().getPluginManager().callEvent(event); // CraftBukkit ++ // Paper end + advancement.value().rewards().grant(this.player); + advancement.value().display().ifPresent((advancementdisplay) -> { +- if (advancementdisplay.shouldAnnounceChat() && this.player.serverLevel().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) { +- this.playerList.broadcastSystemMessage(advancementdisplay.getType().createAnnouncement(advancement, this.player), false); ++ // Paper start - Add Adventure message to PlayerAdvancementDoneEvent ++ if (event.message() != null && this.player.serverLevel().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) { ++ this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false); ++ // Paper end + } + + }); diff --git a/patches/server/0517-Add-EntityBlockStorage-clearEntities.patch b/patches/server/0517-Add-EntityBlockStorage-clearEntities.patch deleted file mode 100644 index 51ffd96ff7..0000000000 --- a/patches/server/0517-Add-EntityBlockStorage-clearEntities.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: Mon, 5 Apr 2021 18:12:29 -0400 -Subject: [PATCH] Add EntityBlockStorage#clearEntities() - - -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 333189cf01ce571993e8152f5851b8c362ba4b70..801528022c902714138c264bc4d05ef0df85912e 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 -@@ -152,6 +152,11 @@ public class BeehiveBlockEntity extends BlockEntity { - return this.stored.size(); - } - -+ // Paper start - Add EntityBlockStorage clearEntities -+ public void clearBees() { -+ this.stored.clear(); -+ } -+ // Paper end - Add EntityBlockStorage clearEntities - public static int getHoneyLevel(BlockState state) { - return (Integer) state.getValue(BeehiveBlock.HONEY_LEVEL); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java -index fbacbef0dd51037fa0af56fedeea50a5c7bed8c7..1a2a05160ba51d9c75f1ae6ae61d944d81428722 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java -@@ -95,4 +95,11 @@ public class CraftBeehive extends CraftBlockEntityState impl - public CraftBeehive copy(Location location) { - return new CraftBeehive(this, location); - } -+ -+ // Paper start - Add EntityBlockStorage clearEntities -+ @Override -+ public void clearEntities() { -+ getSnapshot().clearBees(); -+ } -+ // Paper end - } diff --git a/patches/server/0518-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch b/patches/server/0518-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch deleted file mode 100644 index 9df7276feb..0000000000 --- a/patches/server/0518-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Alvinn8 <42838560+Alvinn8@users.noreply.github.com> -Date: Fri, 8 Jan 2021 20:31:13 +0100 -Subject: [PATCH] Add Adventure message to PlayerAdvancementDoneEvent - - -diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java -index 0fe941b0802f2966ad55509baac124f56ecef999..1dcb8a287be7df2a59b5b4c1345be80637a7f679 100644 ---- a/src/main/java/net/minecraft/server/PlayerAdvancements.java -+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java -@@ -236,11 +236,21 @@ public class PlayerAdvancements { - this.progressChanged.add(advancement); - flag = true; - if (!flag1 && advancementprogress.isDone()) { -- this.player.level().getCraftServer().getPluginManager().callEvent(new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancement.toBukkit())); // CraftBukkit -+ // Paper start - Add Adventure message to PlayerAdvancementDoneEvent -+ final net.kyori.adventure.text.Component message = advancement.value().display().flatMap(info -> { -+ return java.util.Optional.ofNullable( -+ info.shouldAnnounceChat() ? io.papermc.paper.adventure.PaperAdventure.asAdventure(info.getType().createAnnouncement(advancement, this.player)) : null -+ ); -+ }).orElse(null); -+ final org.bukkit.event.player.PlayerAdvancementDoneEvent event = new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancement.toBukkit(), message); -+ this.player.level().getCraftServer().getPluginManager().callEvent(event); // CraftBukkit -+ // Paper end - advancement.value().rewards().grant(this.player); - advancement.value().display().ifPresent((advancementdisplay) -> { -- if (advancementdisplay.shouldAnnounceChat() && this.player.serverLevel().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) { -- this.playerList.broadcastSystemMessage(advancementdisplay.getType().createAnnouncement(advancement, this.player), false); -+ // Paper start - Add Adventure message to PlayerAdvancementDoneEvent -+ if (event.message() != null && this.player.serverLevel().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) { -+ this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false); -+ // Paper end - } - - }); diff --git a/patches/server/0518-Add-HiddenPotionEffect-API.patch b/patches/server/0518-Add-HiddenPotionEffect-API.patch new file mode 100644 index 0000000000..2d0b0d5b03 --- /dev/null +++ b/patches/server/0518-Add-HiddenPotionEffect-API.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tamion <70228790+notTamion@users.noreply.github.com> +Date: Sun, 5 Nov 2023 09:51:28 +0100 +Subject: [PATCH] Add HiddenPotionEffect API + +== AT == +public net.minecraft.world.effect.MobEffectInstance hiddenEffect + +diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java +index 01af4db5d0f17ea2943e5c464d4122a358503bc1..cb11f0624e4e65aa06bfaaec90729ee536cd53a0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java ++++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java +@@ -78,6 +78,7 @@ public class CraftPotionUtil { + + public static MobEffectInstance fromBukkit(PotionEffect effect) { + Holder type = CraftPotionEffectType.bukkitToMinecraftHolder(effect.getType()); ++ // Paper - Note: do not copy over the hidden effect, as this method is only used for applying to entities which we do not want to convert over. + return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()); // Paper + } + +@@ -87,7 +88,7 @@ public class CraftPotionUtil { + int duration = effect.getDuration(); + boolean ambient = effect.isAmbient(); + boolean particles = effect.isVisible(); +- return new PotionEffect(type, duration, amp, ambient, particles, effect.showIcon()); // Paper ++ return new PotionEffect(type, duration, amp, ambient, particles, effect.showIcon(), effect.hiddenEffect == null ? null : toBukkit(effect.hiddenEffect)); // Paper + } + + public static boolean equals(Holder mobEffect, PotionEffectType type) { diff --git a/patches/server/0519-Add-HiddenPotionEffect-API.patch b/patches/server/0519-Add-HiddenPotionEffect-API.patch deleted file mode 100644 index 2d0b0d5b03..0000000000 --- a/patches/server/0519-Add-HiddenPotionEffect-API.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Tamion <70228790+notTamion@users.noreply.github.com> -Date: Sun, 5 Nov 2023 09:51:28 +0100 -Subject: [PATCH] Add HiddenPotionEffect API - -== AT == -public net.minecraft.world.effect.MobEffectInstance hiddenEffect - -diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java -index 01af4db5d0f17ea2943e5c464d4122a358503bc1..cb11f0624e4e65aa06bfaaec90729ee536cd53a0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java -+++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java -@@ -78,6 +78,7 @@ public class CraftPotionUtil { - - public static MobEffectInstance fromBukkit(PotionEffect effect) { - Holder type = CraftPotionEffectType.bukkitToMinecraftHolder(effect.getType()); -+ // Paper - Note: do not copy over the hidden effect, as this method is only used for applying to entities which we do not want to convert over. - return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()); // Paper - } - -@@ -87,7 +88,7 @@ public class CraftPotionUtil { - int duration = effect.getDuration(); - boolean ambient = effect.isAmbient(); - boolean particles = effect.isVisible(); -- return new PotionEffect(type, duration, amp, ambient, particles, effect.showIcon()); // Paper -+ return new PotionEffect(type, duration, amp, ambient, particles, effect.showIcon(), effect.hiddenEffect == null ? null : toBukkit(effect.hiddenEffect)); // Paper - } - - public static boolean equals(Holder mobEffect, PotionEffectType type) { diff --git a/patches/server/0519-Inventory-close.patch b/patches/server/0519-Inventory-close.patch new file mode 100644 index 0000000000..9dcad3d0b1 --- /dev/null +++ b/patches/server/0519-Inventory-close.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 11 May 2021 14:54:56 -0700 +Subject: [PATCH] Inventory#close + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +index f3a1859a1c2adb0448186c322793585dafefe7e0..bc5ec42a54401a2275c05f0f506ba89f00c19ec9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +@@ -439,6 +439,14 @@ public class CraftInventory implements Inventory { + this.clear(i); + } + } ++ // Paper start ++ @Override ++ public int close() { ++ int count = this.inventory.getViewers().size(); ++ com.google.common.collect.Lists.newArrayList(this.inventory.getViewers()).forEach(HumanEntity::closeInventory); ++ return count; ++ } ++ // Paper end + + @Override + public ListIterator iterator() { diff --git a/patches/server/0520-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch b/patches/server/0520-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch new file mode 100644 index 0000000000..cf84510891 --- /dev/null +++ b/patches/server/0520-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch @@ -0,0 +1,130 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MeFisto94 +Date: Tue, 11 May 2021 00:48:33 +0200 +Subject: [PATCH] Add a "should burn in sunlight" API for Phantoms and + Skeletons + + +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 7c80c79a87ec438d0891c5c977e162f272d80039..cb89a95e6ff9db73c912bba04d27657683135153 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -97,9 +97,15 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + + abstract SoundEvent getStepSound(); + ++ // Paper start - shouldBurnInDay API ++ private boolean shouldBurnInDay = true; ++ public boolean shouldBurnInDay() { return shouldBurnInDay; } ++ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } ++ // Paper end - shouldBurnInDay API ++ + @Override + public void aiStep() { +- boolean flag = this.isSunBurnTick(); ++ boolean flag = shouldBurnInDay && this.isSunBurnTick(); // Paper - shouldBurnInDay API + + if (flag) { + ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); +@@ -243,7 +249,20 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + public void readAdditionalSaveData(CompoundTag nbt) { + super.readAdditionalSaveData(nbt); + this.reassessWeaponGoal(); ++ // Paper start - shouldBurnInDay API ++ if (nbt.contains("Paper.ShouldBurnInDay")) { ++ this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); ++ } ++ // Paper end - shouldBurnInDay API ++ } ++ ++ // Paper start - shouldBurnInDay API ++ @Override ++ public void addAdditionalSaveData(CompoundTag nbt) { ++ super.addAdditionalSaveData(nbt); ++ nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); + } ++ // Paper end - shouldBurnInDay API + + @Override + public void setItemSlot(EquipmentSlot slot, ItemStack stack) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java +index 1171a4e45bed0455b29b2cf012fbc2883b16d061..4ff75412452649ebf106ef591cb97dc7ac8175e7 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java +@@ -139,7 +139,7 @@ public class Phantom extends FlyingMob implements Enemy { + + @Override + public void aiStep() { +- if (this.isAlive() && this.isSunBurnTick()) { ++ if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API + this.igniteForSeconds(8.0F); + } + +@@ -165,6 +165,9 @@ public class Phantom extends FlyingMob implements Enemy { + if (nbt.hasUUID("Paper.SpawningEntity")) { + this.spawningEntity = nbt.getUUID("Paper.SpawningEntity"); + } ++ if (nbt.contains("Paper.ShouldBurnInDay")) { ++ this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); ++ } + // Paper end + } + +@@ -179,6 +182,7 @@ public class Phantom extends FlyingMob implements Enemy { + if (this.spawningEntity != null) { + nbt.putUUID("Paper.SpawningEntity", this.spawningEntity); + } ++ nbt.putBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); + // Paper end + } + +@@ -238,6 +242,9 @@ public class Phantom extends FlyingMob implements Enemy { + return this.spawningEntity; + } + public void setSpawningEntity(java.util.UUID entity) { this.spawningEntity = entity; } ++ private boolean shouldBurnInDay = true; ++ public boolean shouldBurnInDay() { return shouldBurnInDay; } ++ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } + // Paper end + + private static enum AttackPhase { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java +index 5ff566186431440c25a26900aba14e4adb642031..5beaa2bb0d58fe477ce8d2de8b77600d3b416d8c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java +@@ -20,4 +20,15 @@ public abstract class CraftAbstractSkeleton extends CraftMonster implements Abst + return (net.minecraft.world.entity.monster.AbstractSkeleton) super.getHandle(); + } + // Paper end ++ // Paper start ++ @Override ++ public boolean shouldBurnInDay() { ++ return getHandle().shouldBurnInDay(); ++ } ++ ++ @Override ++ public void setShouldBurnInDay(boolean shouldBurnInDay) { ++ getHandle().setShouldBurnInDay(shouldBurnInDay); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java +index 305a635b049741ac5e2670060c6818cb2c07e5ab..9304e201db1ec96d0916aa8ea781f3e4bc7991e6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java +@@ -34,5 +34,15 @@ public class CraftPhantom extends CraftFlying implements Phantom, CraftEnemy { + public java.util.UUID getSpawningEntity() { + return getHandle().getSpawningEntity(); + } ++ ++ @Override ++ public boolean shouldBurnInDay() { ++ return getHandle().shouldBurnInDay(); ++ } ++ ++ @Override ++ public void setShouldBurnInDay(boolean shouldBurnInDay) { ++ getHandle().setShouldBurnInDay(shouldBurnInDay); ++ } + // Paper end + } diff --git a/patches/server/0520-Inventory-close.patch b/patches/server/0520-Inventory-close.patch deleted file mode 100644 index 9dcad3d0b1..0000000000 --- a/patches/server/0520-Inventory-close.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 11 May 2021 14:54:56 -0700 -Subject: [PATCH] Inventory#close - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -index f3a1859a1c2adb0448186c322793585dafefe7e0..bc5ec42a54401a2275c05f0f506ba89f00c19ec9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -@@ -439,6 +439,14 @@ public class CraftInventory implements Inventory { - this.clear(i); - } - } -+ // Paper start -+ @Override -+ public int close() { -+ int count = this.inventory.getViewers().size(); -+ com.google.common.collect.Lists.newArrayList(this.inventory.getViewers()).forEach(HumanEntity::closeInventory); -+ return count; -+ } -+ // Paper end - - @Override - public ListIterator iterator() { diff --git a/patches/server/0521-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch b/patches/server/0521-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch deleted file mode 100644 index cf84510891..0000000000 --- a/patches/server/0521-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MeFisto94 -Date: Tue, 11 May 2021 00:48:33 +0200 -Subject: [PATCH] Add a "should burn in sunlight" API for Phantoms and - Skeletons - - -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 7c80c79a87ec438d0891c5c977e162f272d80039..cb89a95e6ff9db73c912bba04d27657683135153 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -97,9 +97,15 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - - abstract SoundEvent getStepSound(); - -+ // Paper start - shouldBurnInDay API -+ private boolean shouldBurnInDay = true; -+ public boolean shouldBurnInDay() { return shouldBurnInDay; } -+ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } -+ // Paper end - shouldBurnInDay API -+ - @Override - public void aiStep() { -- boolean flag = this.isSunBurnTick(); -+ boolean flag = shouldBurnInDay && this.isSunBurnTick(); // Paper - shouldBurnInDay API - - if (flag) { - ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); -@@ -243,7 +249,20 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); - this.reassessWeaponGoal(); -+ // Paper start - shouldBurnInDay API -+ if (nbt.contains("Paper.ShouldBurnInDay")) { -+ this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); -+ } -+ // Paper end - shouldBurnInDay API -+ } -+ -+ // Paper start - shouldBurnInDay API -+ @Override -+ public void addAdditionalSaveData(CompoundTag nbt) { -+ super.addAdditionalSaveData(nbt); -+ nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); - } -+ // Paper end - shouldBurnInDay API - - @Override - public void setItemSlot(EquipmentSlot slot, ItemStack stack) { -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index 1171a4e45bed0455b29b2cf012fbc2883b16d061..4ff75412452649ebf106ef591cb97dc7ac8175e7 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -139,7 +139,7 @@ public class Phantom extends FlyingMob implements Enemy { - - @Override - public void aiStep() { -- if (this.isAlive() && this.isSunBurnTick()) { -+ if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API - this.igniteForSeconds(8.0F); - } - -@@ -165,6 +165,9 @@ public class Phantom extends FlyingMob implements Enemy { - if (nbt.hasUUID("Paper.SpawningEntity")) { - this.spawningEntity = nbt.getUUID("Paper.SpawningEntity"); - } -+ if (nbt.contains("Paper.ShouldBurnInDay")) { -+ this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); -+ } - // Paper end - } - -@@ -179,6 +182,7 @@ public class Phantom extends FlyingMob implements Enemy { - if (this.spawningEntity != null) { - nbt.putUUID("Paper.SpawningEntity", this.spawningEntity); - } -+ nbt.putBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); - // Paper end - } - -@@ -238,6 +242,9 @@ public class Phantom extends FlyingMob implements Enemy { - return this.spawningEntity; - } - public void setSpawningEntity(java.util.UUID entity) { this.spawningEntity = entity; } -+ private boolean shouldBurnInDay = true; -+ public boolean shouldBurnInDay() { return shouldBurnInDay; } -+ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } - // Paper end - - private static enum AttackPhase { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java -index 5ff566186431440c25a26900aba14e4adb642031..5beaa2bb0d58fe477ce8d2de8b77600d3b416d8c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java -@@ -20,4 +20,15 @@ public abstract class CraftAbstractSkeleton extends CraftMonster implements Abst - return (net.minecraft.world.entity.monster.AbstractSkeleton) super.getHandle(); - } - // Paper end -+ // Paper start -+ @Override -+ public boolean shouldBurnInDay() { -+ return getHandle().shouldBurnInDay(); -+ } -+ -+ @Override -+ public void setShouldBurnInDay(boolean shouldBurnInDay) { -+ getHandle().setShouldBurnInDay(shouldBurnInDay); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java -index 305a635b049741ac5e2670060c6818cb2c07e5ab..9304e201db1ec96d0916aa8ea781f3e4bc7991e6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java -@@ -34,5 +34,15 @@ public class CraftPhantom extends CraftFlying implements Phantom, CraftEnemy { - public java.util.UUID getSpawningEntity() { - return getHandle().getSpawningEntity(); - } -+ -+ @Override -+ public boolean shouldBurnInDay() { -+ return getHandle().shouldBurnInDay(); -+ } -+ -+ @Override -+ public void setShouldBurnInDay(boolean shouldBurnInDay) { -+ getHandle().setShouldBurnInDay(shouldBurnInDay); -+ } - // Paper end - } diff --git a/patches/server/0521-Add-basic-Datapack-API.patch b/patches/server/0521-Add-basic-Datapack-API.patch new file mode 100644 index 0000000000..990697b9ea --- /dev/null +++ b/patches/server/0521-Add-basic-Datapack-API.patch @@ -0,0 +1,209 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Connor Linfoot +Date: Sun, 16 May 2021 15:07:34 +0100 +Subject: [PATCH] Add basic Datapack API + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/io/papermc/paper/datapack/PaperDatapack.java b/src/main/java/io/papermc/paper/datapack/PaperDatapack.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8bd8263b51fb2bb364353565b1ba26b3b0d1d55e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datapack/PaperDatapack.java +@@ -0,0 +1,103 @@ ++package io.papermc.paper.datapack; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.event.server.ServerResourcesReloadedEvent; ++import io.papermc.paper.world.flag.PaperFeatureFlagProviderImpl; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.Map; ++import java.util.Set; ++import java.util.concurrent.ConcurrentHashMap; ++import net.kyori.adventure.text.Component; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.packs.repository.Pack; ++import net.minecraft.server.packs.repository.PackSource; ++import org.bukkit.FeatureFlag; ++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 PaperDatapack implements Datapack { ++ ++ private static final Map PACK_SOURCES = new ConcurrentHashMap<>(); ++ static { ++ PACK_SOURCES.put(PackSource.DEFAULT, DatapackSource.DEFAULT); ++ PACK_SOURCES.put(PackSource.BUILT_IN, DatapackSource.BUILT_IN); ++ PACK_SOURCES.put(PackSource.FEATURE, DatapackSource.FEATURE); ++ PACK_SOURCES.put(PackSource.WORLD, DatapackSource.WORLD); ++ PACK_SOURCES.put(PackSource.SERVER, DatapackSource.SERVER); ++ } ++ ++ private final Pack pack; ++ private final boolean enabled; ++ ++ PaperDatapack(final Pack pack, final boolean enabled) { ++ this.pack = pack; ++ this.enabled = enabled; ++ } ++ ++ @Override ++ public String getName() { ++ return this.pack.getId(); ++ } ++ ++ @Override ++ public Component getTitle() { ++ return PaperAdventure.asAdventure(this.pack.getTitle()); ++ } ++ ++ @Override ++ public Component getDescription() { ++ return PaperAdventure.asAdventure(this.pack.getDescription()); ++ } ++ ++ @Override ++ public boolean isRequired() { ++ return this.pack.isRequired(); ++ } ++ ++ @Override ++ public Compatibility getCompatibility() { ++ return Datapack.Compatibility.valueOf(this.pack.getCompatibility().name()); ++ } ++ ++ @Override ++ public Set getRequiredFeatures() { ++ return PaperFeatureFlagProviderImpl.fromNms(this.pack.getRequestedFeatures()); ++ } ++ ++ @Override ++ public boolean isEnabled() { ++ return this.enabled; ++ } ++ ++ @Override ++ public void setEnabled(final boolean enabled) { ++ final MinecraftServer server = MinecraftServer.getServer(); ++ final List enabledPacks = new ArrayList<>(server.getPackRepository().getSelectedPacks()); ++ final @Nullable Pack packToChange = server.getPackRepository().getPack(this.getName()); ++ if (packToChange == null) { ++ throw new IllegalStateException("Cannot toggle state of pack that doesn't exist: " + this.getName()); ++ } ++ if (enabled == enabledPacks.contains(packToChange)) { ++ return; ++ } ++ if (enabled) { ++ packToChange.getDefaultPosition().insert(enabledPacks, packToChange, Pack::selectionConfig, false); // modeled off the default /datapack enable logic ++ } else { ++ enabledPacks.remove(packToChange); ++ } ++ server.reloadResources(enabledPacks.stream().map(Pack::getId).toList(), ServerResourcesReloadedEvent.Cause.PLUGIN); ++ } ++ ++ @Override ++ public DatapackSource getSource() { ++ return PACK_SOURCES.computeIfAbsent(this.pack.location().source(), source -> new DatapackSourceImpl(source.toString())); ++ } ++ ++ @Override ++ public Component computeDisplayName() { ++ return PaperAdventure.asAdventure(this.pack.getChatLink(this.enabled)); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datapack/PaperDatapackManager.java b/src/main/java/io/papermc/paper/datapack/PaperDatapackManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..caa41c525d2b36b5a9f9942380f06c97d5781a93 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datapack/PaperDatapackManager.java +@@ -0,0 +1,55 @@ ++package io.papermc.paper.datapack; ++ ++import com.google.common.collect.Collections2; ++import java.util.Collection; ++import java.util.Collections; ++import java.util.function.Predicate; ++import net.minecraft.server.packs.repository.Pack; ++import net.minecraft.server.packs.repository.PackRepository; ++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 PaperDatapackManager implements DatapackManager { ++ ++ private final PackRepository repository; ++ ++ public PaperDatapackManager(final PackRepository repository) { ++ this.repository = repository; ++ } ++ ++ @Override ++ public void refreshPacks() { ++ this.repository.reload(); ++ } ++ ++ @Override ++ public @Nullable Datapack getPack(final @NonNull String name) { ++ final @Nullable Pack pack = this.repository.getPack(name); ++ if (pack == null) { ++ return null; ++ } ++ return new PaperDatapack(pack, this.repository.getSelectedPacks().contains(pack)); ++ } ++ ++ @Override ++ public Collection getPacks() { ++ final Collection enabledPacks = this.repository.getSelectedPacks(); ++ return this.transformPacks(this.repository.getAvailablePacks(), enabledPacks::contains); ++ } ++ ++ @Override ++ public Collection getEnabledPacks() { ++ return this.transformPacks(this.repository.getSelectedPacks(), pack -> true); ++ } ++ ++ private Collection transformPacks(final Collection packs, final Predicate enabled) { ++ return Collections.unmodifiableCollection( ++ Collections2.transform( ++ packs, ++ pack -> new PaperDatapack(pack, enabled.test(pack)) ++ ) ++ ); ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 3cfacacd1d8fd17ec4b54936afd8124823b1a00b..b4af066a21e4893b5ec146d109b5146b6996a0cf 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -308,6 +308,7 @@ public final class CraftServer implements Server { + private final List playerView; + public int reloadCount; + public Set activeCompatibilities = Collections.emptySet(); ++ private final io.papermc.paper.datapack.PaperDatapackManager datapackManager; // Paper + public static Exception excessiveVelEx; // Paper - Velocity warnings + + static { +@@ -392,6 +393,7 @@ public final class CraftServer implements Server { + if (this.configuration.getBoolean("settings.use-map-color-cache")) { + MapPalette.setMapColorCache(new CraftMapColorCache(this.logger)); + } ++ datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper + } + + public boolean getCommandBlockOverride(String command) { +@@ -3036,5 +3038,11 @@ public final class CraftServer implements Server { + public com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { + return mobGoals; + } ++ ++ @Override ++ public io.papermc.paper.datapack.PaperDatapackManager getDatapackManager() { ++ return datapackManager; ++ } ++ + // Paper end + } diff --git a/patches/server/0522-Add-basic-Datapack-API.patch b/patches/server/0522-Add-basic-Datapack-API.patch deleted file mode 100644 index 990697b9ea..0000000000 --- a/patches/server/0522-Add-basic-Datapack-API.patch +++ /dev/null @@ -1,209 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Connor Linfoot -Date: Sun, 16 May 2021 15:07:34 +0100 -Subject: [PATCH] Add basic Datapack API - -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/io/papermc/paper/datapack/PaperDatapack.java b/src/main/java/io/papermc/paper/datapack/PaperDatapack.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8bd8263b51fb2bb364353565b1ba26b3b0d1d55e ---- /dev/null -+++ b/src/main/java/io/papermc/paper/datapack/PaperDatapack.java -@@ -0,0 +1,103 @@ -+package io.papermc.paper.datapack; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import io.papermc.paper.event.server.ServerResourcesReloadedEvent; -+import io.papermc.paper.world.flag.PaperFeatureFlagProviderImpl; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.Map; -+import java.util.Set; -+import java.util.concurrent.ConcurrentHashMap; -+import net.kyori.adventure.text.Component; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.packs.repository.Pack; -+import net.minecraft.server.packs.repository.PackSource; -+import org.bukkit.FeatureFlag; -+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 PaperDatapack implements Datapack { -+ -+ private static final Map PACK_SOURCES = new ConcurrentHashMap<>(); -+ static { -+ PACK_SOURCES.put(PackSource.DEFAULT, DatapackSource.DEFAULT); -+ PACK_SOURCES.put(PackSource.BUILT_IN, DatapackSource.BUILT_IN); -+ PACK_SOURCES.put(PackSource.FEATURE, DatapackSource.FEATURE); -+ PACK_SOURCES.put(PackSource.WORLD, DatapackSource.WORLD); -+ PACK_SOURCES.put(PackSource.SERVER, DatapackSource.SERVER); -+ } -+ -+ private final Pack pack; -+ private final boolean enabled; -+ -+ PaperDatapack(final Pack pack, final boolean enabled) { -+ this.pack = pack; -+ this.enabled = enabled; -+ } -+ -+ @Override -+ public String getName() { -+ return this.pack.getId(); -+ } -+ -+ @Override -+ public Component getTitle() { -+ return PaperAdventure.asAdventure(this.pack.getTitle()); -+ } -+ -+ @Override -+ public Component getDescription() { -+ return PaperAdventure.asAdventure(this.pack.getDescription()); -+ } -+ -+ @Override -+ public boolean isRequired() { -+ return this.pack.isRequired(); -+ } -+ -+ @Override -+ public Compatibility getCompatibility() { -+ return Datapack.Compatibility.valueOf(this.pack.getCompatibility().name()); -+ } -+ -+ @Override -+ public Set getRequiredFeatures() { -+ return PaperFeatureFlagProviderImpl.fromNms(this.pack.getRequestedFeatures()); -+ } -+ -+ @Override -+ public boolean isEnabled() { -+ return this.enabled; -+ } -+ -+ @Override -+ public void setEnabled(final boolean enabled) { -+ final MinecraftServer server = MinecraftServer.getServer(); -+ final List enabledPacks = new ArrayList<>(server.getPackRepository().getSelectedPacks()); -+ final @Nullable Pack packToChange = server.getPackRepository().getPack(this.getName()); -+ if (packToChange == null) { -+ throw new IllegalStateException("Cannot toggle state of pack that doesn't exist: " + this.getName()); -+ } -+ if (enabled == enabledPacks.contains(packToChange)) { -+ return; -+ } -+ if (enabled) { -+ packToChange.getDefaultPosition().insert(enabledPacks, packToChange, Pack::selectionConfig, false); // modeled off the default /datapack enable logic -+ } else { -+ enabledPacks.remove(packToChange); -+ } -+ server.reloadResources(enabledPacks.stream().map(Pack::getId).toList(), ServerResourcesReloadedEvent.Cause.PLUGIN); -+ } -+ -+ @Override -+ public DatapackSource getSource() { -+ return PACK_SOURCES.computeIfAbsent(this.pack.location().source(), source -> new DatapackSourceImpl(source.toString())); -+ } -+ -+ @Override -+ public Component computeDisplayName() { -+ return PaperAdventure.asAdventure(this.pack.getChatLink(this.enabled)); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/datapack/PaperDatapackManager.java b/src/main/java/io/papermc/paper/datapack/PaperDatapackManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..caa41c525d2b36b5a9f9942380f06c97d5781a93 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/datapack/PaperDatapackManager.java -@@ -0,0 +1,55 @@ -+package io.papermc.paper.datapack; -+ -+import com.google.common.collect.Collections2; -+import java.util.Collection; -+import java.util.Collections; -+import java.util.function.Predicate; -+import net.minecraft.server.packs.repository.Pack; -+import net.minecraft.server.packs.repository.PackRepository; -+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 PaperDatapackManager implements DatapackManager { -+ -+ private final PackRepository repository; -+ -+ public PaperDatapackManager(final PackRepository repository) { -+ this.repository = repository; -+ } -+ -+ @Override -+ public void refreshPacks() { -+ this.repository.reload(); -+ } -+ -+ @Override -+ public @Nullable Datapack getPack(final @NonNull String name) { -+ final @Nullable Pack pack = this.repository.getPack(name); -+ if (pack == null) { -+ return null; -+ } -+ return new PaperDatapack(pack, this.repository.getSelectedPacks().contains(pack)); -+ } -+ -+ @Override -+ public Collection getPacks() { -+ final Collection enabledPacks = this.repository.getSelectedPacks(); -+ return this.transformPacks(this.repository.getAvailablePacks(), enabledPacks::contains); -+ } -+ -+ @Override -+ public Collection getEnabledPacks() { -+ return this.transformPacks(this.repository.getSelectedPacks(), pack -> true); -+ } -+ -+ private Collection transformPacks(final Collection packs, final Predicate enabled) { -+ return Collections.unmodifiableCollection( -+ Collections2.transform( -+ packs, -+ pack -> new PaperDatapack(pack, enabled.test(pack)) -+ ) -+ ); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 3cfacacd1d8fd17ec4b54936afd8124823b1a00b..b4af066a21e4893b5ec146d109b5146b6996a0cf 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -308,6 +308,7 @@ public final class CraftServer implements Server { - private final List playerView; - public int reloadCount; - public Set activeCompatibilities = Collections.emptySet(); -+ private final io.papermc.paper.datapack.PaperDatapackManager datapackManager; // Paper - public static Exception excessiveVelEx; // Paper - Velocity warnings - - static { -@@ -392,6 +393,7 @@ public final class CraftServer implements Server { - if (this.configuration.getBoolean("settings.use-map-color-cache")) { - MapPalette.setMapColorCache(new CraftMapColorCache(this.logger)); - } -+ datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper - } - - public boolean getCommandBlockOverride(String command) { -@@ -3036,5 +3038,11 @@ public final class CraftServer implements Server { - public com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { - return mobGoals; - } -+ -+ @Override -+ public io.papermc.paper.datapack.PaperDatapackManager getDatapackManager() { -+ return datapackManager; -+ } -+ - // Paper end - } diff --git a/patches/server/0522-Add-environment-variable-to-disable-server-gui.patch b/patches/server/0522-Add-environment-variable-to-disable-server-gui.patch new file mode 100644 index 0000000000..186cfa260f --- /dev/null +++ b/patches/server/0522-Add-environment-variable-to-disable-server-gui.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Riley Park +Date: Mon, 17 May 2021 00:34:55 -0700 +Subject: [PATCH] Add environment variable to disable server gui + + +diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java +index da61f3a4ec9bb9726d9d45552b8eada3f87d9e58..c551f6827476b6432ebe1d48e7ca5d168df305c5 100644 +--- a/src/main/java/net/minecraft/server/Main.java ++++ b/src/main/java/net/minecraft/server/Main.java +@@ -320,6 +320,7 @@ public class Main { + */ + boolean flag2 = !optionset.has("nogui") && !optionset.nonOptionArguments().contains("nogui"); + ++ if(!Boolean.parseBoolean(System.getenv().getOrDefault("PAPER_DISABLE_SERVER_GUI", String.valueOf(false)))) // Paper - Add environment variable to disable server gui + if (flag2 && !GraphicsEnvironment.isHeadless()) { + dedicatedserver1.showGui(); + } diff --git a/patches/server/0523-Add-environment-variable-to-disable-server-gui.patch b/patches/server/0523-Add-environment-variable-to-disable-server-gui.patch deleted file mode 100644 index 186cfa260f..0000000000 --- a/patches/server/0523-Add-environment-variable-to-disable-server-gui.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Riley Park -Date: Mon, 17 May 2021 00:34:55 -0700 -Subject: [PATCH] Add environment variable to disable server gui - - -diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index da61f3a4ec9bb9726d9d45552b8eada3f87d9e58..c551f6827476b6432ebe1d48e7ca5d168df305c5 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -320,6 +320,7 @@ public class Main { - */ - boolean flag2 = !optionset.has("nogui") && !optionset.nonOptionArguments().contains("nogui"); - -+ if(!Boolean.parseBoolean(System.getenv().getOrDefault("PAPER_DISABLE_SERVER_GUI", String.valueOf(false)))) // Paper - Add environment variable to disable server gui - if (flag2 && !GraphicsEnvironment.isHeadless()) { - dedicatedserver1.showGui(); - } diff --git a/patches/server/0523-Expand-PlayerGameModeChangeEvent.patch b/patches/server/0523-Expand-PlayerGameModeChangeEvent.patch new file mode 100644 index 0000000000..4f480ddd87 --- /dev/null +++ b/patches/server/0523-Expand-PlayerGameModeChangeEvent.patch @@ -0,0 +1,161 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 15 May 2021 10:04:43 -0700 +Subject: [PATCH] Expand PlayerGameModeChangeEvent + + +diff --git a/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java b/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java +index b95a979f8f58f43e0becedcd843ff8bb992eb455..a046a0b1519806ff3d987e6402f152b60a3a6f4c 100644 +--- a/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java ++++ b/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java +@@ -28,9 +28,13 @@ public class DefaultGameModeCommands { + GameType gameType = minecraftServer.getForcedGameType(); + if (gameType != null) { + for (ServerPlayer serverPlayer : minecraftServer.getPlayerList().getPlayers()) { +- if (serverPlayer.setGameMode(gameType)) { +- i++; ++ // Paper start - Expand PlayerGameModeChangeEvent ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = serverPlayer.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, net.kyori.adventure.text.Component.empty()); ++ if (event != null && event.isCancelled()) { ++ source.sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), false); + } ++ // Paper end - Expand PlayerGameModeChangeEvent ++ i++; + } + } + +diff --git a/src/main/java/net/minecraft/server/commands/GameModeCommand.java b/src/main/java/net/minecraft/server/commands/GameModeCommand.java +index 7f09119bc7d661e08a960dd2bd46006efe752d3e..d1da3600dc07107309b20ebe6e7c0c4da0e8de76 100644 +--- a/src/main/java/net/minecraft/server/commands/GameModeCommand.java ++++ b/src/main/java/net/minecraft/server/commands/GameModeCommand.java +@@ -60,9 +60,14 @@ public class GameModeCommand { + int i = 0; + + for (ServerPlayer serverPlayer : targets) { +- if (serverPlayer.setGameMode(gameMode)) { ++ // Paper start - Expand PlayerGameModeChangeEvent ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = serverPlayer.setGameMode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.COMMAND, net.kyori.adventure.text.Component.empty()); ++ if (event != null && !event.isCancelled()) { + logGamemodeChange(context.getSource(), serverPlayer, gameMode); + i++; ++ } else if (event != null && event.cancelMessage() != null) { ++ context.getSource().sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), true); ++ // Paper end - Expand PlayerGameModeChangeEvent + } + } + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 0e4fe0a2a160c4965cdbfe3d6d375a66c129894d..32fc24fa05660ff941fc02bb3c1827790acbbb1a 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -2315,10 +2315,18 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + } + + public boolean setGameMode(GameType gameMode) { ++ // Paper start - Expand PlayerGameModeChangeEvent ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.setGameMode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null); ++ return event == null ? false : event.isCancelled(); ++ } ++ @Nullable ++ public org.bukkit.event.player.PlayerGameModeChangeEvent setGameMode(GameType gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause, @Nullable net.kyori.adventure.text.Component message) { + boolean flag = this.isSpectator(); + +- if (!this.gameMode.changeGameModeForPlayer(gameMode)) { +- return false; ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.gameMode.changeGameModeForPlayer(gameMode, cause, message); ++ if (event == null || event.isCancelled()) { ++ return null; ++ // Paper end - Expand PlayerGameModeChangeEvent + } else { + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, (float) gameMode.getId())); + if (gameMode == GameType.SPECTATOR) { +@@ -2334,7 +2342,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + + this.onUpdateAbilities(); + this.updateEffectVisibility(); +- return true; ++ return event; // Paper - Expand PlayerGameModeChangeEvent + } + } + +@@ -2783,6 +2791,16 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + } + + public void loadGameTypes(@Nullable CompoundTag nbt) { ++ // Paper start - Expand PlayerGameModeChangeEvent ++ if (this.server.getForcedGameType() != null && this.server.getForcedGameType() != ServerPlayer.readPlayerMode(nbt, "playerGameType")) { ++ if (new org.bukkit.event.player.PlayerGameModeChangeEvent(this.getBukkitEntity(), org.bukkit.GameMode.getByValue(this.server.getDefaultGameType().getId()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null).callEvent()) { ++ this.gameMode.setGameModeForPlayer(this.server.getForcedGameType(), GameType.DEFAULT_MODE); ++ } else { ++ this.gameMode.setGameModeForPlayer(ServerPlayer.readPlayerMode(nbt,"playerGameType"), ServerPlayer.readPlayerMode(nbt, "previousPlayerGameType")); ++ } ++ return; ++ } ++ // Paper end - Expand PlayerGameModeChangeEvent + this.gameMode.setGameModeForPlayer(this.calculateGameModeForNewPlayer(ServerPlayer.readPlayerMode(nbt, "playerGameType")), ServerPlayer.readPlayerMode(nbt, "previousPlayerGameType")); + } + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 546be40a8e4470fb5a6686072cdd342cdaa6fe15..e000a918230187f6841b03b7b0dd73687f3cc15e 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -72,14 +72,21 @@ public class ServerPlayerGameMode { + } + + public boolean changeGameModeForPlayer(GameType gameMode) { ++ // Paper start - Expand PlayerGameModeChangeEvent ++ PlayerGameModeChangeEvent event = this.changeGameModeForPlayer(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null); ++ return event != null && event.isCancelled(); ++ } ++ @Nullable ++ public PlayerGameModeChangeEvent changeGameModeForPlayer(GameType gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause, @Nullable net.kyori.adventure.text.Component cancelMessage) { ++ // Paper end - Expand PlayerGameModeChangeEvent + if (gameMode == this.gameModeForPlayer) { +- return false; ++ return null; // Paper - Expand PlayerGameModeChangeEvent + } else { + // CraftBukkit start +- PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(this.player.getBukkitEntity(), GameMode.getByValue(gameMode.getId())); ++ PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(this.player.getBukkitEntity(), GameMode.getByValue(gameMode.getId()), cause, cancelMessage); // Paper + this.level.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { +- return false; ++ return event; // Paper - Expand PlayerGameModeChangeEvent + } + // CraftBukkit end + this.setGameModeForPlayer(gameMode, this.previousGameModeForPlayer); +@@ -90,7 +97,7 @@ public class ServerPlayerGameMode { + this.player.resetCurrentImpulseContext(); + } + +- return true; ++ return event; // Paper - Expand PlayerGameModeChangeEvent + } + } + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 7864d30a18c76f1170708192e7690cc7b50b15ef..bfd38864cbb205f56a7c5da76990aca06f04a979 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2818,7 +2818,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.player = this.server.getPlayerList().respawn(this.player, false, Entity.RemovalReason.KILLED, RespawnReason.DEATH); // CraftBukkit + this.resetPosition(); + if (this.server.isHardcore()) { +- this.player.setGameMode(GameType.SPECTATOR); ++ this.player.setGameMode(GameType.SPECTATOR, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.HARDCORE_DEATH, null); // Paper - Expand PlayerGameModeChangeEvent + ((GameRules.BooleanValue) this.player.serverLevel().getGameRules().getRule(GameRules.RULE_SPECTATORSGENERATECHUNKS)).set(false, this.player.serverLevel()); // CraftBukkit - per-world + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index c93ec7e97c9af44ed75e7ea4fb1c6c58c2b6bc1a..0b151a66d7419653088526bd72119ebd2d6dd18e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1671,7 +1671,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + Preconditions.checkArgument(mode != null, "GameMode cannot be null"); + if (this.getHandle().connection == null) return; + +- this.getHandle().setGameMode(GameType.byId(mode.getValue())); ++ this.getHandle().setGameMode(GameType.byId(mode.getValue()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.PLUGIN, null); // Paper - Expand PlayerGameModeChangeEvent + } + + @Override diff --git a/patches/server/0524-Expand-PlayerGameModeChangeEvent.patch b/patches/server/0524-Expand-PlayerGameModeChangeEvent.patch deleted file mode 100644 index 3b41fe4053..0000000000 --- a/patches/server/0524-Expand-PlayerGameModeChangeEvent.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 15 May 2021 10:04:43 -0700 -Subject: [PATCH] Expand PlayerGameModeChangeEvent - - -diff --git a/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java b/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java -index b95a979f8f58f43e0becedcd843ff8bb992eb455..a046a0b1519806ff3d987e6402f152b60a3a6f4c 100644 ---- a/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java -+++ b/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java -@@ -28,9 +28,13 @@ public class DefaultGameModeCommands { - GameType gameType = minecraftServer.getForcedGameType(); - if (gameType != null) { - for (ServerPlayer serverPlayer : minecraftServer.getPlayerList().getPlayers()) { -- if (serverPlayer.setGameMode(gameType)) { -- i++; -+ // Paper start - Expand PlayerGameModeChangeEvent -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = serverPlayer.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, net.kyori.adventure.text.Component.empty()); -+ if (event != null && event.isCancelled()) { -+ source.sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), false); - } -+ // Paper end - Expand PlayerGameModeChangeEvent -+ i++; - } - } - -diff --git a/src/main/java/net/minecraft/server/commands/GameModeCommand.java b/src/main/java/net/minecraft/server/commands/GameModeCommand.java -index 7f09119bc7d661e08a960dd2bd46006efe752d3e..d1da3600dc07107309b20ebe6e7c0c4da0e8de76 100644 ---- a/src/main/java/net/minecraft/server/commands/GameModeCommand.java -+++ b/src/main/java/net/minecraft/server/commands/GameModeCommand.java -@@ -60,9 +60,14 @@ public class GameModeCommand { - int i = 0; - - for (ServerPlayer serverPlayer : targets) { -- if (serverPlayer.setGameMode(gameMode)) { -+ // Paper start - Expand PlayerGameModeChangeEvent -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = serverPlayer.setGameMode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.COMMAND, net.kyori.adventure.text.Component.empty()); -+ if (event != null && !event.isCancelled()) { - logGamemodeChange(context.getSource(), serverPlayer, gameMode); - i++; -+ } else if (event != null && event.cancelMessage() != null) { -+ context.getSource().sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), true); -+ // Paper end - Expand PlayerGameModeChangeEvent - } - } - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index c22dce8b30c8af3e37b497b0d97c6ceef0295883..2125f9dc87dbf31a66004dc859788f584e099e73 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -2315,10 +2315,18 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - } - - public boolean setGameMode(GameType gameMode) { -+ // Paper start - Expand PlayerGameModeChangeEvent -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.setGameMode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null); -+ return event == null ? false : event.isCancelled(); -+ } -+ @Nullable -+ public org.bukkit.event.player.PlayerGameModeChangeEvent setGameMode(GameType gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause, @Nullable net.kyori.adventure.text.Component message) { - boolean flag = this.isSpectator(); - -- if (!this.gameMode.changeGameModeForPlayer(gameMode)) { -- return false; -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.gameMode.changeGameModeForPlayer(gameMode, cause, message); -+ if (event == null || event.isCancelled()) { -+ return null; -+ // Paper end - Expand PlayerGameModeChangeEvent - } else { - this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, (float) gameMode.getId())); - if (gameMode == GameType.SPECTATOR) { -@@ -2334,7 +2342,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - - this.onUpdateAbilities(); - this.updateEffectVisibility(); -- return true; -+ return event; // Paper - Expand PlayerGameModeChangeEvent - } - } - -@@ -2783,6 +2791,16 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - } - - public void loadGameTypes(@Nullable CompoundTag nbt) { -+ // Paper start - Expand PlayerGameModeChangeEvent -+ if (this.server.getForcedGameType() != null && this.server.getForcedGameType() != ServerPlayer.readPlayerMode(nbt, "playerGameType")) { -+ if (new org.bukkit.event.player.PlayerGameModeChangeEvent(this.getBukkitEntity(), org.bukkit.GameMode.getByValue(this.server.getDefaultGameType().getId()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null).callEvent()) { -+ this.gameMode.setGameModeForPlayer(this.server.getForcedGameType(), GameType.DEFAULT_MODE); -+ } else { -+ this.gameMode.setGameModeForPlayer(ServerPlayer.readPlayerMode(nbt,"playerGameType"), ServerPlayer.readPlayerMode(nbt, "previousPlayerGameType")); -+ } -+ return; -+ } -+ // Paper end - Expand PlayerGameModeChangeEvent - this.gameMode.setGameModeForPlayer(this.calculateGameModeForNewPlayer(ServerPlayer.readPlayerMode(nbt, "playerGameType")), ServerPlayer.readPlayerMode(nbt, "previousPlayerGameType")); - } - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 546be40a8e4470fb5a6686072cdd342cdaa6fe15..e000a918230187f6841b03b7b0dd73687f3cc15e 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -72,14 +72,21 @@ public class ServerPlayerGameMode { - } - - public boolean changeGameModeForPlayer(GameType gameMode) { -+ // Paper start - Expand PlayerGameModeChangeEvent -+ PlayerGameModeChangeEvent event = this.changeGameModeForPlayer(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null); -+ return event != null && event.isCancelled(); -+ } -+ @Nullable -+ public PlayerGameModeChangeEvent changeGameModeForPlayer(GameType gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause, @Nullable net.kyori.adventure.text.Component cancelMessage) { -+ // Paper end - Expand PlayerGameModeChangeEvent - if (gameMode == this.gameModeForPlayer) { -- return false; -+ return null; // Paper - Expand PlayerGameModeChangeEvent - } else { - // CraftBukkit start -- PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(this.player.getBukkitEntity(), GameMode.getByValue(gameMode.getId())); -+ PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(this.player.getBukkitEntity(), GameMode.getByValue(gameMode.getId()), cause, cancelMessage); // Paper - this.level.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { -- return false; -+ return event; // Paper - Expand PlayerGameModeChangeEvent - } - // CraftBukkit end - this.setGameModeForPlayer(gameMode, this.previousGameModeForPlayer); -@@ -90,7 +97,7 @@ public class ServerPlayerGameMode { - this.player.resetCurrentImpulseContext(); - } - -- return true; -+ return event; // Paper - Expand PlayerGameModeChangeEvent - } - } - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 7864d30a18c76f1170708192e7690cc7b50b15ef..bfd38864cbb205f56a7c5da76990aca06f04a979 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2818,7 +2818,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.player = this.server.getPlayerList().respawn(this.player, false, Entity.RemovalReason.KILLED, RespawnReason.DEATH); // CraftBukkit - this.resetPosition(); - if (this.server.isHardcore()) { -- this.player.setGameMode(GameType.SPECTATOR); -+ this.player.setGameMode(GameType.SPECTATOR, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.HARDCORE_DEATH, null); // Paper - Expand PlayerGameModeChangeEvent - ((GameRules.BooleanValue) this.player.serverLevel().getGameRules().getRule(GameRules.RULE_SPECTATORSGENERATECHUNKS)).set(false, this.player.serverLevel()); // CraftBukkit - per-world - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index c93ec7e97c9af44ed75e7ea4fb1c6c58c2b6bc1a..0b151a66d7419653088526bd72119ebd2d6dd18e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1671,7 +1671,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - Preconditions.checkArgument(mode != null, "GameMode cannot be null"); - if (this.getHandle().connection == null) return; - -- this.getHandle().setGameMode(GameType.byId(mode.getValue())); -+ this.getHandle().setGameMode(GameType.byId(mode.getValue()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.PLUGIN, null); // Paper - Expand PlayerGameModeChangeEvent - } - - @Override diff --git a/patches/server/0524-ItemStack-repair-check-API.patch b/patches/server/0524-ItemStack-repair-check-API.patch new file mode 100644 index 0000000000..33c7e11836 --- /dev/null +++ b/patches/server/0524-ItemStack-repair-check-API.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 15 May 2021 22:11:11 -0700 +Subject: [PATCH] ItemStack repair check API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 30f2ddb66385718304b4b0302f7efcafd54bc42a..fa4e8cb2d53e0ac4e15a8188454ceed0afafe503 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -548,6 +548,14 @@ public final class CraftMagicNumbers implements UnsafeValues { + public int getProtocolVersion() { + return net.minecraft.SharedConstants.getCurrentVersion().getProtocolVersion(); + } ++ ++ @Override ++ public boolean isValidRepairItemStack(org.bukkit.inventory.ItemStack itemToBeRepaired, org.bukkit.inventory.ItemStack repairMaterial) { ++ if (!itemToBeRepaired.getType().isItem() || !repairMaterial.getType().isItem()) { ++ return false; ++ } ++ return CraftItemStack.unwrap(itemToBeRepaired).isValidRepairItem(CraftItemStack.unwrap(repairMaterial)); ++ } + // Paper end + + /** +diff --git a/src/test/java/io/papermc/paper/util/ItemStackRepairCheckTest.java b/src/test/java/io/papermc/paper/util/ItemStackRepairCheckTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..04e2568816f1fbe090b40e5a55d8d4effc045740 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/util/ItemStackRepairCheckTest.java +@@ -0,0 +1,41 @@ ++package io.papermc.paper.util; ++ ++import org.bukkit.Material; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.support.environment.VanillaFeature; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertFalse; ++import static org.junit.jupiter.api.Assertions.assertTrue; ++ ++@VanillaFeature ++public class ItemStackRepairCheckTest { ++ ++ @Test ++ public void testIsRepariableBy() { ++ ItemStack diamondPick = new ItemStack(Material.DIAMOND_PICKAXE); ++ ++ assertTrue(diamondPick.isRepairableBy(new ItemStack(Material.DIAMOND)), "diamond pick isn't repairable by a diamond"); ++ } ++ ++ @Test ++ public void testCanRepair() { ++ ItemStack diamond = new ItemStack(Material.DIAMOND); ++ ++ assertTrue(diamond.canRepair(new ItemStack(Material.DIAMOND_AXE)), "diamond can't repair a diamond axe"); ++ } ++ ++ @Test ++ public void testIsNotRepairableBy() { ++ ItemStack notDiamondPick = new ItemStack(Material.ACACIA_SAPLING); ++ ++ assertFalse(notDiamondPick.isRepairableBy(new ItemStack(Material.DIAMOND)), "acacia sapling is repairable by a diamond"); ++ } ++ ++ @Test ++ public void testCanNotRepair() { ++ ItemStack diamond = new ItemStack(Material.DIAMOND); ++ ++ assertFalse(diamond.canRepair(new ItemStack(Material.OAK_BUTTON)), "diamond can repair oak button"); ++ } ++} diff --git a/patches/server/0525-ItemStack-repair-check-API.patch b/patches/server/0525-ItemStack-repair-check-API.patch deleted file mode 100644 index 33c7e11836..0000000000 --- a/patches/server/0525-ItemStack-repair-check-API.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 15 May 2021 22:11:11 -0700 -Subject: [PATCH] ItemStack repair check API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 30f2ddb66385718304b4b0302f7efcafd54bc42a..fa4e8cb2d53e0ac4e15a8188454ceed0afafe503 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -548,6 +548,14 @@ public final class CraftMagicNumbers implements UnsafeValues { - public int getProtocolVersion() { - return net.minecraft.SharedConstants.getCurrentVersion().getProtocolVersion(); - } -+ -+ @Override -+ public boolean isValidRepairItemStack(org.bukkit.inventory.ItemStack itemToBeRepaired, org.bukkit.inventory.ItemStack repairMaterial) { -+ if (!itemToBeRepaired.getType().isItem() || !repairMaterial.getType().isItem()) { -+ return false; -+ } -+ return CraftItemStack.unwrap(itemToBeRepaired).isValidRepairItem(CraftItemStack.unwrap(repairMaterial)); -+ } - // Paper end - - /** -diff --git a/src/test/java/io/papermc/paper/util/ItemStackRepairCheckTest.java b/src/test/java/io/papermc/paper/util/ItemStackRepairCheckTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..04e2568816f1fbe090b40e5a55d8d4effc045740 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/util/ItemStackRepairCheckTest.java -@@ -0,0 +1,41 @@ -+package io.papermc.paper.util; -+ -+import org.bukkit.Material; -+import org.bukkit.inventory.ItemStack; -+import org.bukkit.support.environment.VanillaFeature; -+import org.junit.jupiter.api.Test; -+ -+import static org.junit.jupiter.api.Assertions.assertFalse; -+import static org.junit.jupiter.api.Assertions.assertTrue; -+ -+@VanillaFeature -+public class ItemStackRepairCheckTest { -+ -+ @Test -+ public void testIsRepariableBy() { -+ ItemStack diamondPick = new ItemStack(Material.DIAMOND_PICKAXE); -+ -+ assertTrue(diamondPick.isRepairableBy(new ItemStack(Material.DIAMOND)), "diamond pick isn't repairable by a diamond"); -+ } -+ -+ @Test -+ public void testCanRepair() { -+ ItemStack diamond = new ItemStack(Material.DIAMOND); -+ -+ assertTrue(diamond.canRepair(new ItemStack(Material.DIAMOND_AXE)), "diamond can't repair a diamond axe"); -+ } -+ -+ @Test -+ public void testIsNotRepairableBy() { -+ ItemStack notDiamondPick = new ItemStack(Material.ACACIA_SAPLING); -+ -+ assertFalse(notDiamondPick.isRepairableBy(new ItemStack(Material.DIAMOND)), "acacia sapling is repairable by a diamond"); -+ } -+ -+ @Test -+ public void testCanNotRepair() { -+ ItemStack diamond = new ItemStack(Material.DIAMOND); -+ -+ assertFalse(diamond.canRepair(new ItemStack(Material.OAK_BUTTON)), "diamond can repair oak button"); -+ } -+} diff --git a/patches/server/0525-More-Enchantment-API.patch b/patches/server/0525-More-Enchantment-API.patch new file mode 100644 index 0000000000..a3bf8f8e7e --- /dev/null +++ b/patches/server/0525-More-Enchantment-API.patch @@ -0,0 +1,105 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 6 May 2021 19:57:58 -0700 +Subject: [PATCH] More Enchantment API + +== AT == +public net.minecraft.world.item.enchantment.Enchantment definition + +Co-authored-by: Luis +Co-authored-by: Janet Blackquill + +diff --git a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java +index 59c9c970b83f62245d860994c4ac0c21dcc15398..4221a1e9cba35c8dc58e51e162e7fcbd0e8b31af 100644 +--- a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java ++++ b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java +@@ -5,6 +5,7 @@ import java.util.Locale; + import net.minecraft.Util; + import net.minecraft.core.Holder; + import net.minecraft.core.registries.Registries; ++import net.minecraft.network.chat.contents.TranslatableContents; + import net.minecraft.tags.EnchantmentTags; + import org.bukkit.NamespacedKey; + import org.bukkit.Registry; +@@ -90,7 +91,7 @@ public class CraftEnchantment extends Enchantment implements Handleable getActiveSlotGroups() { ++ return this.getHandle().definition().slots().stream() ++ .map(org.bukkit.craftbukkit.CraftEquipmentSlot::getSlot) ++ .collect(java.util.stream.Collectors.toSet()); ++ } ++ // Paper end - more Enchantment API ++ + @Override + public String getTranslationKey() { + return Util.makeDescriptionId("enchantment", this.handle.unwrapKey().get().location()); diff --git a/patches/server/0526-More-Enchantment-API.patch b/patches/server/0526-More-Enchantment-API.patch deleted file mode 100644 index a3bf8f8e7e..0000000000 --- a/patches/server/0526-More-Enchantment-API.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 6 May 2021 19:57:58 -0700 -Subject: [PATCH] More Enchantment API - -== AT == -public net.minecraft.world.item.enchantment.Enchantment definition - -Co-authored-by: Luis -Co-authored-by: Janet Blackquill - -diff --git a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java -index 59c9c970b83f62245d860994c4ac0c21dcc15398..4221a1e9cba35c8dc58e51e162e7fcbd0e8b31af 100644 ---- a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java -+++ b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java -@@ -5,6 +5,7 @@ import java.util.Locale; - import net.minecraft.Util; - import net.minecraft.core.Holder; - import net.minecraft.core.registries.Registries; -+import net.minecraft.network.chat.contents.TranslatableContents; - import net.minecraft.tags.EnchantmentTags; - import org.bukkit.NamespacedKey; - import org.bukkit.Registry; -@@ -90,7 +91,7 @@ public class CraftEnchantment extends Enchantment implements Handleable getActiveSlotGroups() { -+ return this.getHandle().definition().slots().stream() -+ .map(org.bukkit.craftbukkit.CraftEquipmentSlot::getSlot) -+ .collect(java.util.stream.Collectors.toSet()); -+ } -+ // Paper end - more Enchantment API -+ - @Override - public String getTranslationKey() { - return Util.makeDescriptionId("enchantment", this.handle.unwrapKey().get().location()); diff --git a/patches/server/0526-Move-range-check-for-block-placing-up.patch b/patches/server/0526-Move-range-check-for-block-placing-up.patch new file mode 100644 index 0000000000..8bb305c92a --- /dev/null +++ b/patches/server/0526-Move-range-check-for-block-placing-up.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Wed, 8 Jun 2022 10:52:18 +0200 +Subject: [PATCH] Move range check for block placing up + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index bfd38864cbb205f56a7c5da76990aca06f04a979..b0739538a19e6401111750f833f1b88846c06b49 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1814,6 +1814,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + if (itemstack.isItemEnabled(worldserver.enabledFeatures())) { + BlockHitResult movingobjectpositionblock = packet.getHitResult(); + Vec3 vec3d = movingobjectpositionblock.getLocation(); ++ // Paper start - improve distance check ++ if (!Double.isFinite(vec3d.x) || !Double.isFinite(vec3d.y) || !Double.isFinite(vec3d.z)) { ++ return; ++ } ++ // Paper end - improve distance check + BlockPos blockposition = movingobjectpositionblock.getBlockPos(); + + if (this.player.canInteractWithBlock(blockposition, 1.0D)) { diff --git a/patches/server/0527-Add-Mob-lookAt-API.patch b/patches/server/0527-Add-Mob-lookAt-API.patch new file mode 100644 index 0000000000..8a8ba9fdcd --- /dev/null +++ b/patches/server/0527-Add-Mob-lookAt-API.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 14 May 2021 13:42:17 -0500 +Subject: [PATCH] Add Mob#lookAt API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +index c67673772c876dab7c015dcdfb75b297d3c4fbad..bd739428a7e5e35ebcdb70cd187379b3d222339b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +@@ -97,5 +97,53 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { + public boolean isInDaylight() { + return getHandle().isSunBurnTick(); + } ++ ++ @Override ++ public void lookAt(@org.jetbrains.annotations.NotNull org.bukkit.Location location) { ++ com.google.common.base.Preconditions.checkNotNull(location, "location cannot be null"); ++ com.google.common.base.Preconditions.checkArgument(location.getWorld().equals(getWorld()), "location in a different world"); ++ getHandle().getLookControl().setLookAt(location.getX(), location.getY(), location.getZ()); ++ } ++ ++ @Override ++ public void lookAt(@org.jetbrains.annotations.NotNull org.bukkit.Location location, float headRotationSpeed, float maxHeadPitch) { ++ com.google.common.base.Preconditions.checkNotNull(location, "location cannot be null"); ++ com.google.common.base.Preconditions.checkArgument(location.getWorld().equals(getWorld()), "location in a different world"); ++ getHandle().getLookControl().setLookAt(location.getX(), location.getY(), location.getZ(), headRotationSpeed, maxHeadPitch); ++ } ++ ++ @Override ++ public void lookAt(@org.jetbrains.annotations.NotNull org.bukkit.entity.Entity entity) { ++ com.google.common.base.Preconditions.checkNotNull(entity, "entity cannot be null"); ++ com.google.common.base.Preconditions.checkArgument(entity.getWorld().equals(getWorld()), "entity in a different world"); ++ getHandle().getLookControl().setLookAt(((CraftEntity) entity).getHandle()); ++ } ++ ++ @Override ++ public void lookAt(@org.jetbrains.annotations.NotNull org.bukkit.entity.Entity entity, float headRotationSpeed, float maxHeadPitch) { ++ com.google.common.base.Preconditions.checkNotNull(entity, "entity cannot be null"); ++ com.google.common.base.Preconditions.checkArgument(entity.getWorld().equals(getWorld()), "entity in a different world"); ++ getHandle().getLookControl().setLookAt(((CraftEntity) entity).getHandle(), headRotationSpeed, maxHeadPitch); ++ } ++ ++ @Override ++ public void lookAt(double x, double y, double z) { ++ getHandle().getLookControl().setLookAt(x, y, z); ++ } ++ ++ @Override ++ public void lookAt(double x, double y, double z, float headRotationSpeed, float maxHeadPitch) { ++ getHandle().getLookControl().setLookAt(x, y, z, headRotationSpeed, maxHeadPitch); ++ } ++ ++ @Override ++ public int getHeadRotationSpeed() { ++ return getHandle().getHeadRotSpeed(); ++ } ++ ++ @Override ++ public int getMaxHeadPitch() { ++ return getHandle().getMaxHeadXRot(); ++ } + // Paper end + } diff --git a/patches/server/0527-Move-range-check-for-block-placing-up.patch b/patches/server/0527-Move-range-check-for-block-placing-up.patch deleted file mode 100644 index 8bb305c92a..0000000000 --- a/patches/server/0527-Move-range-check-for-block-placing-up.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Wed, 8 Jun 2022 10:52:18 +0200 -Subject: [PATCH] Move range check for block placing up - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index bfd38864cbb205f56a7c5da76990aca06f04a979..b0739538a19e6401111750f833f1b88846c06b49 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1814,6 +1814,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - if (itemstack.isItemEnabled(worldserver.enabledFeatures())) { - BlockHitResult movingobjectpositionblock = packet.getHitResult(); - Vec3 vec3d = movingobjectpositionblock.getLocation(); -+ // Paper start - improve distance check -+ if (!Double.isFinite(vec3d.x) || !Double.isFinite(vec3d.y) || !Double.isFinite(vec3d.z)) { -+ return; -+ } -+ // Paper end - improve distance check - BlockPos blockposition = movingobjectpositionblock.getBlockPos(); - - if (this.player.canInteractWithBlock(blockposition, 1.0D)) { diff --git a/patches/server/0528-Add-Mob-lookAt-API.patch b/patches/server/0528-Add-Mob-lookAt-API.patch deleted file mode 100644 index 8a8ba9fdcd..0000000000 --- a/patches/server/0528-Add-Mob-lookAt-API.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 14 May 2021 13:42:17 -0500 -Subject: [PATCH] Add Mob#lookAt API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -index c67673772c876dab7c015dcdfb75b297d3c4fbad..bd739428a7e5e35ebcdb70cd187379b3d222339b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -@@ -97,5 +97,53 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { - public boolean isInDaylight() { - return getHandle().isSunBurnTick(); - } -+ -+ @Override -+ public void lookAt(@org.jetbrains.annotations.NotNull org.bukkit.Location location) { -+ com.google.common.base.Preconditions.checkNotNull(location, "location cannot be null"); -+ com.google.common.base.Preconditions.checkArgument(location.getWorld().equals(getWorld()), "location in a different world"); -+ getHandle().getLookControl().setLookAt(location.getX(), location.getY(), location.getZ()); -+ } -+ -+ @Override -+ public void lookAt(@org.jetbrains.annotations.NotNull org.bukkit.Location location, float headRotationSpeed, float maxHeadPitch) { -+ com.google.common.base.Preconditions.checkNotNull(location, "location cannot be null"); -+ com.google.common.base.Preconditions.checkArgument(location.getWorld().equals(getWorld()), "location in a different world"); -+ getHandle().getLookControl().setLookAt(location.getX(), location.getY(), location.getZ(), headRotationSpeed, maxHeadPitch); -+ } -+ -+ @Override -+ public void lookAt(@org.jetbrains.annotations.NotNull org.bukkit.entity.Entity entity) { -+ com.google.common.base.Preconditions.checkNotNull(entity, "entity cannot be null"); -+ com.google.common.base.Preconditions.checkArgument(entity.getWorld().equals(getWorld()), "entity in a different world"); -+ getHandle().getLookControl().setLookAt(((CraftEntity) entity).getHandle()); -+ } -+ -+ @Override -+ public void lookAt(@org.jetbrains.annotations.NotNull org.bukkit.entity.Entity entity, float headRotationSpeed, float maxHeadPitch) { -+ com.google.common.base.Preconditions.checkNotNull(entity, "entity cannot be null"); -+ com.google.common.base.Preconditions.checkArgument(entity.getWorld().equals(getWorld()), "entity in a different world"); -+ getHandle().getLookControl().setLookAt(((CraftEntity) entity).getHandle(), headRotationSpeed, maxHeadPitch); -+ } -+ -+ @Override -+ public void lookAt(double x, double y, double z) { -+ getHandle().getLookControl().setLookAt(x, y, z); -+ } -+ -+ @Override -+ public void lookAt(double x, double y, double z, float headRotationSpeed, float maxHeadPitch) { -+ getHandle().getLookControl().setLookAt(x, y, z, headRotationSpeed, maxHeadPitch); -+ } -+ -+ @Override -+ public int getHeadRotationSpeed() { -+ return getHandle().getHeadRotSpeed(); -+ } -+ -+ @Override -+ public int getMaxHeadPitch() { -+ return getHandle().getMaxHeadXRot(); -+ } - // Paper end - } diff --git a/patches/server/0528-Correctly-check-if-bucket-dispenses-will-succeed-for.patch b/patches/server/0528-Correctly-check-if-bucket-dispenses-will-succeed-for.patch new file mode 100644 index 0000000000..cc05cc8b4e --- /dev/null +++ b/patches/server/0528-Correctly-check-if-bucket-dispenses-will-succeed-for.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 1 Jan 2024 12:57:19 -0800 +Subject: [PATCH] Correctly check if bucket dispenses will succeed for event + +Upstream incorrectly checks if the bucket place will succeed +in order to fire the BlockDispenseEvent. This patch corrects +that. + +diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +index ab002c2a5cfb029bd61b7d8e0548fd135b95cdcc..780f83d50aac70c819608f4c79c08ef34664d7b0 100644 +--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +@@ -330,7 +330,13 @@ public interface DispenseItemBehavior { + int y = blockposition.getY(); + int z = blockposition.getZ(); + BlockState iblockdata = worldserver.getBlockState(blockposition); +- if (iblockdata.isAir() || iblockdata.canBeReplaced() || (dispensiblecontaineritem instanceof BucketItem && iblockdata.getBlock() instanceof LiquidBlockContainer && ((LiquidBlockContainer) iblockdata.getBlock()).canPlaceLiquid((Player) null, worldserver, blockposition, iblockdata, ((BucketItem) dispensiblecontaineritem).content))) { ++ // 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(); ++ /* Taken from BucketItem#emptyContents */ ++ boolean willEmptyBucketItem = dispensiblecontaineritem instanceof final BucketItem bucketItem && bucketItem.content instanceof net.minecraft.world.level.material.FlowingFluid && (iblockdata.isAir() || iblockdata.canBeReplaced(bucketItem.content) || (iblockdata.getBlock() instanceof LiquidBlockContainer liquidBlockContainer && liquidBlockContainer.canPlaceLiquid(null, worldserver, blockposition, iblockdata, bucketItem.content))); ++ if (willEmptyContentsSolidBucketItem || willEmptyBucketItem) { ++ // Paper end - correctly check if the bucket place will succeed + org.bukkit.block.Block block = CraftBlock.at(worldserver, pointer.pos()); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); + diff --git a/patches/server/0529-Add-Unix-domain-socket-support.patch b/patches/server/0529-Add-Unix-domain-socket-support.patch new file mode 100644 index 0000000000..445d662e9c --- /dev/null +++ b/patches/server/0529-Add-Unix-domain-socket-support.patch @@ -0,0 +1,137 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Steinborn +Date: Tue, 11 May 2021 17:39:22 -0400 +Subject: [PATCH] Add Unix domain socket support + + +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 761663514b98a1c0a0a905150411aff450a0cc50..21d6f728d6ecd35a05933e9406a386c36135a456 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -233,6 +233,20 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + this.setEnforceWhitelist(dedicatedserverproperties.enforceWhitelist); + // this.worldData.setGameType(dedicatedserverproperties.gamemode); // CraftBukkit - moved to world loading + DedicatedServer.LOGGER.info("Default game type: {}", dedicatedserverproperties.gamemode); ++ // Paper start - Unix domain socket support ++ java.net.SocketAddress bindAddress; ++ if (this.getLocalIp().startsWith("unix:")) { ++ if (!io.netty.channel.epoll.Epoll.isAvailable()) { ++ DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); ++ DedicatedServer.LOGGER.error("You are trying to use a Unix domain socket but you're not on a supported OS."); ++ return false; ++ } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && !org.spigotmc.SpigotConfig.bungee) { ++ DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); ++ DedicatedServer.LOGGER.error("Unix domain sockets require IPs to be forwarded from a proxy."); ++ return false; ++ } ++ bindAddress = new io.netty.channel.unix.DomainSocketAddress(this.getLocalIp().substring("unix:".length())); ++ } else { + InetAddress inetaddress = null; + + if (!this.getLocalIp().isEmpty()) { +@@ -242,12 +256,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + if (this.getPort() < 0) { + this.setPort(dedicatedserverproperties.serverPort); + } ++ bindAddress = new java.net.InetSocketAddress(inetaddress, this.getPort()); ++ } ++ // Paper end - Unix domain socket support + + this.initializeKeyPair(); + DedicatedServer.LOGGER.info("Starting Minecraft server on {}:{}", this.getLocalIp().isEmpty() ? "*" : this.getLocalIp(), this.getPort()); + + try { +- this.getConnection().startTcpServerListener(inetaddress, this.getPort()); ++ this.getConnection().bind(bindAddress); // Paper - Unix domain socket support + } catch (IOException ioexception) { + DedicatedServer.LOGGER.warn("**** FAILED TO BIND TO PORT!"); + DedicatedServer.LOGGER.warn("The exception was: {}", ioexception.toString()); +diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +index d6d7f1c446ba5507f67038ff27775ba75156f4a7..c63c194c44646e6bc1a59426552787011fc2ced5 100644 +--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java ++++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +@@ -76,7 +76,12 @@ public class ServerConnectionListener { + this.running = true; + } + ++ // Paper start - Unix domain socket support + public void startTcpServerListener(@Nullable InetAddress address, int port) throws IOException { ++ bind(new java.net.InetSocketAddress(address, port)); ++ } ++ public void bind(java.net.SocketAddress address) throws IOException { ++ // Paper end - Unix domain socket support + List list = this.channels; + + synchronized (this.channels) { +@@ -84,7 +89,13 @@ public class ServerConnectionListener { + EventLoopGroup eventloopgroup; + + if (Epoll.isAvailable() && this.server.isEpollEnabled()) { ++ // Paper start - Unix domain socket support ++ if (address instanceof io.netty.channel.unix.DomainSocketAddress) { ++ oclass = io.netty.channel.epoll.EpollServerDomainSocketChannel.class; ++ } else { + oclass = EpollServerSocketChannel.class; ++ } ++ // Paper end - Unix domain socket support + eventloopgroup = (EventLoopGroup) ServerConnectionListener.SERVER_EPOLL_EVENT_GROUP.get(); + ServerConnectionListener.LOGGER.info("Using epoll channel type"); + } else { +@@ -117,7 +128,7 @@ public class ServerConnectionListener { + ((Connection) object).setListenerForServerboundHandshake(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object)); + io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper - Add Channel initialization listeners + } +- }).group(eventloopgroup).localAddress(address, port)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit ++ }).group(eventloopgroup).localAddress(address)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit // Paper - Unix domain socket support + } + } + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index b0739538a19e6401111750f833f1b88846c06b49..5e809ac566834307ced0c56727c42fc712f026df 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2631,6 +2631,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + // Spigot Start + public SocketAddress getRawAddress() + { ++ // Paper start - Unix domain socket support; this can be nullable in the case of a Unix domain socket, so if it is, fake something ++ if (connection.channel.remoteAddress() == null) { ++ return new java.net.InetSocketAddress(java.net.InetAddress.getLoopbackAddress(), 0); ++ } ++ // Paper end - Unix domain socket support + return this.connection.channel.remoteAddress(); + } + // Spigot End +diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java +index a5bbea6a073e00c10c3c5facd997eb8473fd9a5f..ddf42645402afefc0f5caebc684b191eef9d6ec2 100644 +--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java +@@ -81,6 +81,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL + this.connection.setupOutboundProtocol(LoginProtocols.CLIENTBOUND); + // CraftBukkit start - Connection throttle + try { ++ if (!(this.connection.channel.localAddress() instanceof io.netty.channel.unix.DomainSocketAddress)) { // Paper - Unix domain socket support; the connection throttle is useless when you have a Unix domain socket + long currentTime = System.currentTimeMillis(); + long connectionThrottle = this.server.server.getConnectionThrottle(); + InetAddress address = ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getAddress(); +@@ -109,6 +110,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL + } + } + } ++ } // Paper - Unix domain socket support + } catch (Throwable t) { + org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t); + } +@@ -166,8 +168,11 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL + if (!handledByEvent && proxyLogicEnabled) { // Paper + // if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above! + if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.BYPASS_HOSTCHECK || ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) { // Paper - Add bypass host check ++ // Paper start - Unix domain socket support ++ java.net.SocketAddress socketAddress = this.connection.getRemoteAddress(); + this.connection.hostname = split[0]; +- this.connection.address = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getPort()); ++ this.connection.address = new java.net.InetSocketAddress(split[1], socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0); ++ // Paper end - Unix domain socket support + this.connection.spoofedUUID = com.mojang.util.UndashedUuid.fromStringLenient( split[2] ); + } else + { diff --git a/patches/server/0529-Correctly-check-if-bucket-dispenses-will-succeed-for.patch b/patches/server/0529-Correctly-check-if-bucket-dispenses-will-succeed-for.patch deleted file mode 100644 index cc05cc8b4e..0000000000 --- a/patches/server/0529-Correctly-check-if-bucket-dispenses-will-succeed-for.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 1 Jan 2024 12:57:19 -0800 -Subject: [PATCH] Correctly check if bucket dispenses will succeed for event - -Upstream incorrectly checks if the bucket place will succeed -in order to fire the BlockDispenseEvent. This patch corrects -that. - -diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index ab002c2a5cfb029bd61b7d8e0548fd135b95cdcc..780f83d50aac70c819608f4c79c08ef34664d7b0 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -330,7 +330,13 @@ public interface DispenseItemBehavior { - int y = blockposition.getY(); - int z = blockposition.getZ(); - BlockState iblockdata = worldserver.getBlockState(blockposition); -- if (iblockdata.isAir() || iblockdata.canBeReplaced() || (dispensiblecontaineritem instanceof BucketItem && iblockdata.getBlock() instanceof LiquidBlockContainer && ((LiquidBlockContainer) iblockdata.getBlock()).canPlaceLiquid((Player) null, worldserver, blockposition, iblockdata, ((BucketItem) dispensiblecontaineritem).content))) { -+ // 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(); -+ /* Taken from BucketItem#emptyContents */ -+ boolean willEmptyBucketItem = dispensiblecontaineritem instanceof final BucketItem bucketItem && bucketItem.content instanceof net.minecraft.world.level.material.FlowingFluid && (iblockdata.isAir() || iblockdata.canBeReplaced(bucketItem.content) || (iblockdata.getBlock() instanceof LiquidBlockContainer liquidBlockContainer && liquidBlockContainer.canPlaceLiquid(null, worldserver, blockposition, iblockdata, bucketItem.content))); -+ if (willEmptyContentsSolidBucketItem || willEmptyBucketItem) { -+ // Paper end - correctly check if the bucket place will succeed - org.bukkit.block.Block block = CraftBlock.at(worldserver, pointer.pos()); - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); - diff --git a/patches/server/0530-Add-EntityInsideBlockEvent.patch b/patches/server/0530-Add-EntityInsideBlockEvent.patch new file mode 100644 index 0000000000..980fe20f4d --- /dev/null +++ b/patches/server/0530-Add-EntityInsideBlockEvent.patch @@ -0,0 +1,306 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 8 May 2021 18:02:36 -0700 +Subject: [PATCH] Add EntityInsideBlockEvent + + +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 7f0811bc22d78cdc0aca4c6869c90252d8a59eed..c8ca41cd81a72f9bff40f5c1b3bfc1189bf51f98 100644 +--- a/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java +@@ -128,6 +128,7 @@ public abstract class BaseFireBlock extends Block { + + @Override + 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.fireImmune()) { + if (entity.getRemainingFireTicks() < 0) { + entity.setRemainingFireTicks(entity.getRemainingFireTicks() + 1); +diff --git a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java +index cd3d9e69653afba51a55a3dfc6764b712b8df859..9afa811579ac2e556b5c5c23b3b49587439dfadc 100644 +--- a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java +@@ -77,6 +77,7 @@ public abstract class BasePressurePlateBlock extends Block { + + @Override + 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 (!world.isClientSide) { + int i = this.getSignalForState(state); + +diff --git a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java +index 87083f7de53e32713b54315803ccd414db2debc8..9e3f1441d62128535112621bf259c24f1a90595b 100644 +--- a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java +@@ -180,6 +180,7 @@ public class BigDripleafBlock extends HorizontalDirectionalBlock implements Bone + + @Override + 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 (!world.isClientSide) { + if (state.getValue(BigDripleafBlock.TILT) == Tilt.NONE && BigDripleafBlock.canEntityTilt(pos, entity) && !world.hasNeighborSignal(pos)) { + // CraftBukkit start - tilt dripleaf +diff --git a/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java b/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java +index c2d8caee4acb878aaa43c0cdc6f6a37555b69a12..385da0585f409ee453f10d45f5837cdc09adc21b 100644 +--- a/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java +@@ -48,6 +48,7 @@ public class BubbleColumnBlock extends Block implements BucketPickup { + + @Override + 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 + BlockState blockState = world.getBlockState(pos.above()); + if (blockState.isAir()) { + entity.onAboveBubbleCol(state.getValue(DRAG_DOWN)); +diff --git a/src/main/java/net/minecraft/world/level/block/ButtonBlock.java b/src/main/java/net/minecraft/world/level/block/ButtonBlock.java +index e210c210b733fc968b9c3816bb1f9755d76660ef..061a8f8b58d9fa7959333e2f59d3b7ee03cbf92d 100644 +--- a/src/main/java/net/minecraft/world/level/block/ButtonBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/ButtonBlock.java +@@ -208,6 +208,7 @@ public class ButtonBlock extends FaceAttachedHorizontalDirectionalBlock { + + @Override + 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 (!world.isClientSide && this.type.canButtonBeActivatedByArrows() && !(Boolean) state.getValue(ButtonBlock.POWERED)) { + this.checkPressed(state, world, pos); + } +diff --git a/src/main/java/net/minecraft/world/level/block/CactusBlock.java b/src/main/java/net/minecraft/world/level/block/CactusBlock.java +index de1b64e0cbe7f2de63f04262428c9e6ec340916e..c045b1cccf0047dbef8c04d5a28d31d53389054f 100644 +--- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java +@@ -122,6 +122,7 @@ public class CactusBlock extends Block { + + @Override + 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 + entity.hurt(world.damageSources().cactus().directBlock(world, pos), 1.0F); // CraftBukkit + } + +diff --git a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java +index e03e2f1d84b4f12d78974b90eb4b741818cdac17..1b94f26e78db062f80d806b82f714a815b4710ff 100644 +--- a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java +@@ -112,6 +112,7 @@ public class CampfireBlock extends BaseEntityBlock implements SimpleWaterloggedB + + @Override + 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 ((Boolean) state.getValue(CampfireBlock.LIT) && entity instanceof LivingEntity) { + entity.hurt(world.damageSources().campfire().directBlock(world, pos), (float) this.fireDamage); // CraftBukkit + } +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 91dd550de860fd16585218814eae0b9dc877c77d..6fe896079c0ae622976c2055f8d13cda5ed3ea3d 100644 +--- a/src/main/java/net/minecraft/world/level/block/CropBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java +@@ -174,6 +174,7 @@ public class CropBlock extends BushBlock implements BonemealableBlock { + + @Override + 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 (world instanceof ServerLevel worldserver) { + if (entity instanceof Ravager && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit + worldserver.destroyBlock(pos, true, entity); +diff --git a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java +index 1e2f56b5c40c3dc72bc38354160f8e7de1f4f5cf..fa1c4defd0d4e4cd888eb26eed131539d0ed573f 100644 +--- a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java +@@ -52,6 +52,7 @@ public class DetectorRailBlock extends BaseRailBlock { + + @Override + 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 (!world.isClientSide) { + if (!(Boolean) state.getValue(DetectorRailBlock.POWERED)) { + this.checkPressed(world, pos, state); +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 b27b09fcb895b72c51335bdcb095f0f3bd3a190b..58b2454ac5bd3400559aba3c64f228f41f6218ae 100644 +--- a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java +@@ -92,6 +92,7 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal { + + @Override + 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)) { + BlockEntity tileentity = world.getBlockEntity(pos); + +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 8887d35d188510cf10da3dc46b0b56373ac346bd..8ca226641588a88c8b068a7acac9d7e92b077144 100644 +--- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java +@@ -68,6 +68,7 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { + + @Override + 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)) { + // CraftBukkit start - Entity in portal + EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); +diff --git a/src/main/java/net/minecraft/world/level/block/EyeblossomBlock.java b/src/main/java/net/minecraft/world/level/block/EyeblossomBlock.java +index be3ddd70a68c43cd8db5d8a25e7d5d7e7b91751d..efe3f34a32fd01c9edba937b4b8ea25f51d86ba0 100644 +--- a/src/main/java/net/minecraft/world/level/block/EyeblossomBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/EyeblossomBlock.java +@@ -100,6 +100,7 @@ public class EyeblossomBlock extends FlowerBlock { + + @Override + 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 (!world.isClientSide() + && world.getDifficulty() != Difficulty.PEACEFUL + && entity instanceof Bee bee +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 aee71779f31def5f1ef7438cf06219d1de7092ec..34be6b349722240e99f91d28067578aa0b4bd1fe 100644 +--- a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java +@@ -89,6 +89,7 @@ public class FrogspawnBlock extends Block { + + @Override + 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.getType().equals(EntityType.FALLING_BLOCK)) { + this.destroyBlock(world, pos); + } +diff --git a/src/main/java/net/minecraft/world/level/block/HoneyBlock.java b/src/main/java/net/minecraft/world/level/block/HoneyBlock.java +index 3ddf43a8afe8f00ca910d7838356dfc6d007a4f9..5c360c6768582c1a35431739613e9b406875cc21 100644 +--- a/src/main/java/net/minecraft/world/level/block/HoneyBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/HoneyBlock.java +@@ -60,6 +60,7 @@ public class HoneyBlock extends HalfTransparentBlock { + + @Override + 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 (this.isSlidingDown(pos, entity)) { + this.maybeDoSlideAchievement(entity, pos); + this.doSlideMovement(entity); +diff --git a/src/main/java/net/minecraft/world/level/block/HopperBlock.java b/src/main/java/net/minecraft/world/level/block/HopperBlock.java +index 882e7e6c7fa77eef109f8203f22edfa9536a96f8..9da02e643948aaea91307e28eb83177aa5d0ecec 100644 +--- a/src/main/java/net/minecraft/world/level/block/HopperBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/HopperBlock.java +@@ -178,6 +178,7 @@ public class HopperBlock extends BaseEntityBlock { + + @Override + 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 + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof HopperBlockEntity) { + HopperBlockEntity.entityInside(world, pos, state, entity, (HopperBlockEntity)blockEntity); +diff --git a/src/main/java/net/minecraft/world/level/block/LavaCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LavaCauldronBlock.java +index 7bf2c33a194517d4e52511fe32a8434cbed0361f..d29a62775913922ffb8e3c58ae0db7e37f77226e 100644 +--- a/src/main/java/net/minecraft/world/level/block/LavaCauldronBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/LavaCauldronBlock.java +@@ -32,6 +32,7 @@ public class LavaCauldronBlock extends AbstractCauldronBlock { + + @Override + 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 (this.isEntityInsideContent(state, pos, entity)) { + entity.lavaHurt(); + } +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 c088d713e80f16ead333ea5283f7f95a2de08523..4ab73a083eba2ad3e12526af0a0dbcfba5cf6c14 100644 +--- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java +@@ -67,6 +67,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { + + @Override + 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 (world instanceof ServerLevel worldserver) { + if (entity.isOnFire() && this.isEntityInsideContent(state, pos, entity)) { + // CraftBukkit start - moved down +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 e404722c119631e31c0519111ccd5f1682c2638d..151025a407a07271bc205955f0ce06f84231563b 100644 +--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +@@ -115,6 +115,7 @@ public class NetherPortalBlock extends Block implements Portal { + + @Override + 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)) { + // CraftBukkit start - Entity in portal + EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); +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 3825b25c7417e4c2e5a25154879199b155a4921f..972d8833127090c01d620cab10b3eca3d3601710 100644 +--- a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java +@@ -107,6 +107,7 @@ public class PitcherCropBlock extends DoublePlantBlock implements BonemealableBl + + @Override + public 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 (world instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { + serverLevel.destroyBlock(pos, true, entity); + } +diff --git a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java +index aaf9350a096022c87ccb788d657c1ae6a7b53a47..53f1a7ed6b4bd6e2d8460531226aabf249994c02 100644 +--- a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java +@@ -59,6 +59,7 @@ public class PowderSnowBlock extends Block implements BucketPickup { + + @Override + 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 instanceof LivingEntity) || entity.getInBlockState().is((Block) this)) { + entity.makeStuckInBlock(state, new Vec3(0.8999999761581421D, 1.5D, 0.8999999761581421D)); + if (world.isClientSide) { +diff --git a/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java b/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java +index a044a2d7e5cb7027394c95c495c59530bc5e18ce..265c85413da04dbc7292a0af934a8b665b2fced5 100644 +--- a/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java +@@ -84,6 +84,7 @@ public class SweetBerryBushBlock extends BushBlock implements BonemealableBlock + + @Override + 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 instanceof LivingEntity && entity.getType() != EntityType.FOX && entity.getType() != EntityType.BEE) { + entity.makeStuckInBlock(state, new Vec3(0.800000011920929D, 0.75D, 0.800000011920929D)); + if (world instanceof ServerLevel) { +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 93777f83cdd2de30ccf597fadd8418853954d1ce..f079e5a9aa098225acf09ed9b4aa7ddbc2381270 100644 +--- a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java +@@ -141,6 +141,7 @@ public class TripWireBlock extends Block { + + @Override + 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 (!world.isClientSide) { + if (!(Boolean) state.getValue(TripWireBlock.POWERED)) { + this.checkPressed(world, pos, List.of(entity)); +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 34599b88011aff718f5a6373229489ea3d947ff7..674d710ff88db5eced9e017284d1b7ec7a4fe7cd 100644 +--- a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java +@@ -33,6 +33,7 @@ public class WaterlilyBlock extends BushBlock { + + @Override + 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 + super.entityInside(state, world, pos, entity); + if (world instanceof ServerLevel && entity instanceof AbstractBoat) { + // CraftBukkit start +diff --git a/src/main/java/net/minecraft/world/level/block/WebBlock.java b/src/main/java/net/minecraft/world/level/block/WebBlock.java +index 4b621793da3d6fbc44f90df863b099ba992930fb..fc209fab3ed1ccb35706a5529ec23ad8b902e491 100644 +--- a/src/main/java/net/minecraft/world/level/block/WebBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/WebBlock.java +@@ -24,6 +24,7 @@ public class WebBlock extends Block { + + @Override + 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 + Vec3 vec3 = new Vec3(0.25, 0.05F, 0.25); + if (entity instanceof LivingEntity livingEntity && livingEntity.hasEffect(MobEffects.WEAVING)) { + vec3 = new Vec3(0.5, 0.25, 0.5); +diff --git a/src/main/java/net/minecraft/world/level/block/WitherRoseBlock.java b/src/main/java/net/minecraft/world/level/block/WitherRoseBlock.java +index b42924ebdd0f5369151b8a37f0070dec7f402073..8b79b2b7766d873b7e689309d936982fc1724686 100644 +--- a/src/main/java/net/minecraft/world/level/block/WitherRoseBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/WitherRoseBlock.java +@@ -63,6 +63,7 @@ public class WitherRoseBlock extends FlowerBlock { + + @Override + 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 (world instanceof ServerLevel worldserver) { + if (world.getDifficulty() != Difficulty.PEACEFUL && entity instanceof LivingEntity entityliving) { + if (!entityliving.isInvulnerableTo(worldserver, world.damageSources().wither())) { diff --git a/patches/server/0530-Add-Unix-domain-socket-support.patch b/patches/server/0530-Add-Unix-domain-socket-support.patch deleted file mode 100644 index 445d662e9c..0000000000 --- a/patches/server/0530-Add-Unix-domain-socket-support.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrew Steinborn -Date: Tue, 11 May 2021 17:39:22 -0400 -Subject: [PATCH] Add Unix domain socket support - - -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 761663514b98a1c0a0a905150411aff450a0cc50..21d6f728d6ecd35a05933e9406a386c36135a456 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -233,6 +233,20 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - this.setEnforceWhitelist(dedicatedserverproperties.enforceWhitelist); - // this.worldData.setGameType(dedicatedserverproperties.gamemode); // CraftBukkit - moved to world loading - DedicatedServer.LOGGER.info("Default game type: {}", dedicatedserverproperties.gamemode); -+ // Paper start - Unix domain socket support -+ java.net.SocketAddress bindAddress; -+ if (this.getLocalIp().startsWith("unix:")) { -+ if (!io.netty.channel.epoll.Epoll.isAvailable()) { -+ DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); -+ DedicatedServer.LOGGER.error("You are trying to use a Unix domain socket but you're not on a supported OS."); -+ return false; -+ } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && !org.spigotmc.SpigotConfig.bungee) { -+ DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); -+ DedicatedServer.LOGGER.error("Unix domain sockets require IPs to be forwarded from a proxy."); -+ return false; -+ } -+ bindAddress = new io.netty.channel.unix.DomainSocketAddress(this.getLocalIp().substring("unix:".length())); -+ } else { - InetAddress inetaddress = null; - - if (!this.getLocalIp().isEmpty()) { -@@ -242,12 +256,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - if (this.getPort() < 0) { - this.setPort(dedicatedserverproperties.serverPort); - } -+ bindAddress = new java.net.InetSocketAddress(inetaddress, this.getPort()); -+ } -+ // Paper end - Unix domain socket support - - this.initializeKeyPair(); - DedicatedServer.LOGGER.info("Starting Minecraft server on {}:{}", this.getLocalIp().isEmpty() ? "*" : this.getLocalIp(), this.getPort()); - - try { -- this.getConnection().startTcpServerListener(inetaddress, this.getPort()); -+ this.getConnection().bind(bindAddress); // Paper - Unix domain socket support - } catch (IOException ioexception) { - DedicatedServer.LOGGER.warn("**** FAILED TO BIND TO PORT!"); - DedicatedServer.LOGGER.warn("The exception was: {}", ioexception.toString()); -diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index d6d7f1c446ba5507f67038ff27775ba75156f4a7..c63c194c44646e6bc1a59426552787011fc2ced5 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -76,7 +76,12 @@ public class ServerConnectionListener { - this.running = true; - } - -+ // Paper start - Unix domain socket support - public void startTcpServerListener(@Nullable InetAddress address, int port) throws IOException { -+ bind(new java.net.InetSocketAddress(address, port)); -+ } -+ public void bind(java.net.SocketAddress address) throws IOException { -+ // Paper end - Unix domain socket support - List list = this.channels; - - synchronized (this.channels) { -@@ -84,7 +89,13 @@ public class ServerConnectionListener { - EventLoopGroup eventloopgroup; - - if (Epoll.isAvailable() && this.server.isEpollEnabled()) { -+ // Paper start - Unix domain socket support -+ if (address instanceof io.netty.channel.unix.DomainSocketAddress) { -+ oclass = io.netty.channel.epoll.EpollServerDomainSocketChannel.class; -+ } else { - oclass = EpollServerSocketChannel.class; -+ } -+ // Paper end - Unix domain socket support - eventloopgroup = (EventLoopGroup) ServerConnectionListener.SERVER_EPOLL_EVENT_GROUP.get(); - ServerConnectionListener.LOGGER.info("Using epoll channel type"); - } else { -@@ -117,7 +128,7 @@ public class ServerConnectionListener { - ((Connection) object).setListenerForServerboundHandshake(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object)); - io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper - Add Channel initialization listeners - } -- }).group(eventloopgroup).localAddress(address, port)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit -+ }).group(eventloopgroup).localAddress(address)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit // Paper - Unix domain socket support - } - } - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index b0739538a19e6401111750f833f1b88846c06b49..5e809ac566834307ced0c56727c42fc712f026df 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2631,6 +2631,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - // Spigot Start - public SocketAddress getRawAddress() - { -+ // Paper start - Unix domain socket support; this can be nullable in the case of a Unix domain socket, so if it is, fake something -+ if (connection.channel.remoteAddress() == null) { -+ return new java.net.InetSocketAddress(java.net.InetAddress.getLoopbackAddress(), 0); -+ } -+ // Paper end - Unix domain socket support - return this.connection.channel.remoteAddress(); - } - // Spigot End -diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java -index a5bbea6a073e00c10c3c5facd997eb8473fd9a5f..ddf42645402afefc0f5caebc684b191eef9d6ec2 100644 ---- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java -@@ -81,6 +81,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL - this.connection.setupOutboundProtocol(LoginProtocols.CLIENTBOUND); - // CraftBukkit start - Connection throttle - try { -+ if (!(this.connection.channel.localAddress() instanceof io.netty.channel.unix.DomainSocketAddress)) { // Paper - Unix domain socket support; the connection throttle is useless when you have a Unix domain socket - long currentTime = System.currentTimeMillis(); - long connectionThrottle = this.server.server.getConnectionThrottle(); - InetAddress address = ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getAddress(); -@@ -109,6 +110,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL - } - } - } -+ } // Paper - Unix domain socket support - } catch (Throwable t) { - org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t); - } -@@ -166,8 +168,11 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL - if (!handledByEvent && proxyLogicEnabled) { // Paper - // if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above! - if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.BYPASS_HOSTCHECK || ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) { // Paper - Add bypass host check -+ // Paper start - Unix domain socket support -+ java.net.SocketAddress socketAddress = this.connection.getRemoteAddress(); - this.connection.hostname = split[0]; -- this.connection.address = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getPort()); -+ this.connection.address = new java.net.InetSocketAddress(split[1], socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0); -+ // Paper end - Unix domain socket support - this.connection.spoofedUUID = com.mojang.util.UndashedUuid.fromStringLenient( split[2] ); - } else - { diff --git a/patches/server/0531-Add-EntityInsideBlockEvent.patch b/patches/server/0531-Add-EntityInsideBlockEvent.patch deleted file mode 100644 index 980fe20f4d..0000000000 --- a/patches/server/0531-Add-EntityInsideBlockEvent.patch +++ /dev/null @@ -1,306 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 8 May 2021 18:02:36 -0700 -Subject: [PATCH] Add EntityInsideBlockEvent - - -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 7f0811bc22d78cdc0aca4c6869c90252d8a59eed..c8ca41cd81a72f9bff40f5c1b3bfc1189bf51f98 100644 ---- a/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BaseFireBlock.java -@@ -128,6 +128,7 @@ public abstract class BaseFireBlock extends Block { - - @Override - 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.fireImmune()) { - if (entity.getRemainingFireTicks() < 0) { - entity.setRemainingFireTicks(entity.getRemainingFireTicks() + 1); -diff --git a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java -index cd3d9e69653afba51a55a3dfc6764b712b8df859..9afa811579ac2e556b5c5c23b3b49587439dfadc 100644 ---- a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java -@@ -77,6 +77,7 @@ public abstract class BasePressurePlateBlock extends Block { - - @Override - 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 (!world.isClientSide) { - int i = this.getSignalForState(state); - -diff --git a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java -index 87083f7de53e32713b54315803ccd414db2debc8..9e3f1441d62128535112621bf259c24f1a90595b 100644 ---- a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java -@@ -180,6 +180,7 @@ public class BigDripleafBlock extends HorizontalDirectionalBlock implements Bone - - @Override - 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 (!world.isClientSide) { - if (state.getValue(BigDripleafBlock.TILT) == Tilt.NONE && BigDripleafBlock.canEntityTilt(pos, entity) && !world.hasNeighborSignal(pos)) { - // CraftBukkit start - tilt dripleaf -diff --git a/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java b/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java -index c2d8caee4acb878aaa43c0cdc6f6a37555b69a12..385da0585f409ee453f10d45f5837cdc09adc21b 100644 ---- a/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java -@@ -48,6 +48,7 @@ public class BubbleColumnBlock extends Block implements BucketPickup { - - @Override - 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 - BlockState blockState = world.getBlockState(pos.above()); - if (blockState.isAir()) { - entity.onAboveBubbleCol(state.getValue(DRAG_DOWN)); -diff --git a/src/main/java/net/minecraft/world/level/block/ButtonBlock.java b/src/main/java/net/minecraft/world/level/block/ButtonBlock.java -index e210c210b733fc968b9c3816bb1f9755d76660ef..061a8f8b58d9fa7959333e2f59d3b7ee03cbf92d 100644 ---- a/src/main/java/net/minecraft/world/level/block/ButtonBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ButtonBlock.java -@@ -208,6 +208,7 @@ public class ButtonBlock extends FaceAttachedHorizontalDirectionalBlock { - - @Override - 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 (!world.isClientSide && this.type.canButtonBeActivatedByArrows() && !(Boolean) state.getValue(ButtonBlock.POWERED)) { - this.checkPressed(state, world, pos); - } -diff --git a/src/main/java/net/minecraft/world/level/block/CactusBlock.java b/src/main/java/net/minecraft/world/level/block/CactusBlock.java -index de1b64e0cbe7f2de63f04262428c9e6ec340916e..c045b1cccf0047dbef8c04d5a28d31d53389054f 100644 ---- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java -@@ -122,6 +122,7 @@ public class CactusBlock extends Block { - - @Override - 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 - entity.hurt(world.damageSources().cactus().directBlock(world, pos), 1.0F); // CraftBukkit - } - -diff --git a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java -index e03e2f1d84b4f12d78974b90eb4b741818cdac17..1b94f26e78db062f80d806b82f714a815b4710ff 100644 ---- a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java -@@ -112,6 +112,7 @@ public class CampfireBlock extends BaseEntityBlock implements SimpleWaterloggedB - - @Override - 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 ((Boolean) state.getValue(CampfireBlock.LIT) && entity instanceof LivingEntity) { - entity.hurt(world.damageSources().campfire().directBlock(world, pos), (float) this.fireDamage); // CraftBukkit - } -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 91dd550de860fd16585218814eae0b9dc877c77d..6fe896079c0ae622976c2055f8d13cda5ed3ea3d 100644 ---- a/src/main/java/net/minecraft/world/level/block/CropBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java -@@ -174,6 +174,7 @@ public class CropBlock extends BushBlock implements BonemealableBlock { - - @Override - 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 (world instanceof ServerLevel worldserver) { - if (entity instanceof Ravager && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit - worldserver.destroyBlock(pos, true, entity); -diff --git a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java -index 1e2f56b5c40c3dc72bc38354160f8e7de1f4f5cf..fa1c4defd0d4e4cd888eb26eed131539d0ed573f 100644 ---- a/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DetectorRailBlock.java -@@ -52,6 +52,7 @@ public class DetectorRailBlock extends BaseRailBlock { - - @Override - 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 (!world.isClientSide) { - if (!(Boolean) state.getValue(DetectorRailBlock.POWERED)) { - this.checkPressed(world, pos, state); -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 b27b09fcb895b72c51335bdcb095f0f3bd3a190b..58b2454ac5bd3400559aba3c64f228f41f6218ae 100644 ---- a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java -@@ -92,6 +92,7 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal { - - @Override - 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)) { - BlockEntity tileentity = world.getBlockEntity(pos); - -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 8887d35d188510cf10da3dc46b0b56373ac346bd..8ca226641588a88c8b068a7acac9d7e92b077144 100644 ---- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -@@ -68,6 +68,7 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { - - @Override - 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)) { - // CraftBukkit start - Entity in portal - EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); -diff --git a/src/main/java/net/minecraft/world/level/block/EyeblossomBlock.java b/src/main/java/net/minecraft/world/level/block/EyeblossomBlock.java -index be3ddd70a68c43cd8db5d8a25e7d5d7e7b91751d..efe3f34a32fd01c9edba937b4b8ea25f51d86ba0 100644 ---- a/src/main/java/net/minecraft/world/level/block/EyeblossomBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EyeblossomBlock.java -@@ -100,6 +100,7 @@ public class EyeblossomBlock extends FlowerBlock { - - @Override - 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 (!world.isClientSide() - && world.getDifficulty() != Difficulty.PEACEFUL - && entity instanceof Bee bee -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 aee71779f31def5f1ef7438cf06219d1de7092ec..34be6b349722240e99f91d28067578aa0b4bd1fe 100644 ---- a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java -@@ -89,6 +89,7 @@ public class FrogspawnBlock extends Block { - - @Override - 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.getType().equals(EntityType.FALLING_BLOCK)) { - this.destroyBlock(world, pos); - } -diff --git a/src/main/java/net/minecraft/world/level/block/HoneyBlock.java b/src/main/java/net/minecraft/world/level/block/HoneyBlock.java -index 3ddf43a8afe8f00ca910d7838356dfc6d007a4f9..5c360c6768582c1a35431739613e9b406875cc21 100644 ---- a/src/main/java/net/minecraft/world/level/block/HoneyBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/HoneyBlock.java -@@ -60,6 +60,7 @@ public class HoneyBlock extends HalfTransparentBlock { - - @Override - 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 (this.isSlidingDown(pos, entity)) { - this.maybeDoSlideAchievement(entity, pos); - this.doSlideMovement(entity); -diff --git a/src/main/java/net/minecraft/world/level/block/HopperBlock.java b/src/main/java/net/minecraft/world/level/block/HopperBlock.java -index 882e7e6c7fa77eef109f8203f22edfa9536a96f8..9da02e643948aaea91307e28eb83177aa5d0ecec 100644 ---- a/src/main/java/net/minecraft/world/level/block/HopperBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/HopperBlock.java -@@ -178,6 +178,7 @@ public class HopperBlock extends BaseEntityBlock { - - @Override - 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 - BlockEntity blockEntity = world.getBlockEntity(pos); - if (blockEntity instanceof HopperBlockEntity) { - HopperBlockEntity.entityInside(world, pos, state, entity, (HopperBlockEntity)blockEntity); -diff --git a/src/main/java/net/minecraft/world/level/block/LavaCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LavaCauldronBlock.java -index 7bf2c33a194517d4e52511fe32a8434cbed0361f..d29a62775913922ffb8e3c58ae0db7e37f77226e 100644 ---- a/src/main/java/net/minecraft/world/level/block/LavaCauldronBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LavaCauldronBlock.java -@@ -32,6 +32,7 @@ public class LavaCauldronBlock extends AbstractCauldronBlock { - - @Override - 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 (this.isEntityInsideContent(state, pos, entity)) { - entity.lavaHurt(); - } -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 c088d713e80f16ead333ea5283f7f95a2de08523..4ab73a083eba2ad3e12526af0a0dbcfba5cf6c14 100644 ---- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java -@@ -67,6 +67,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock { - - @Override - 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 (world instanceof ServerLevel worldserver) { - if (entity.isOnFire() && this.isEntityInsideContent(state, pos, entity)) { - // CraftBukkit start - moved down -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 e404722c119631e31c0519111ccd5f1682c2638d..151025a407a07271bc205955f0ce06f84231563b 100644 ---- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -@@ -115,6 +115,7 @@ public class NetherPortalBlock extends Block implements Portal { - - @Override - 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)) { - // CraftBukkit start - Entity in portal - EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); -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 3825b25c7417e4c2e5a25154879199b155a4921f..972d8833127090c01d620cab10b3eca3d3601710 100644 ---- a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java -@@ -107,6 +107,7 @@ public class PitcherCropBlock extends DoublePlantBlock implements BonemealableBl - - @Override - public 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 (world instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { - serverLevel.destroyBlock(pos, true, entity); - } -diff --git a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java -index aaf9350a096022c87ccb788d657c1ae6a7b53a47..53f1a7ed6b4bd6e2d8460531226aabf249994c02 100644 ---- a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java -@@ -59,6 +59,7 @@ public class PowderSnowBlock extends Block implements BucketPickup { - - @Override - 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 instanceof LivingEntity) || entity.getInBlockState().is((Block) this)) { - entity.makeStuckInBlock(state, new Vec3(0.8999999761581421D, 1.5D, 0.8999999761581421D)); - if (world.isClientSide) { -diff --git a/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java b/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java -index a044a2d7e5cb7027394c95c495c59530bc5e18ce..265c85413da04dbc7292a0af934a8b665b2fced5 100644 ---- a/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java -@@ -84,6 +84,7 @@ public class SweetBerryBushBlock extends BushBlock implements BonemealableBlock - - @Override - 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 instanceof LivingEntity && entity.getType() != EntityType.FOX && entity.getType() != EntityType.BEE) { - entity.makeStuckInBlock(state, new Vec3(0.800000011920929D, 0.75D, 0.800000011920929D)); - if (world instanceof ServerLevel) { -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 93777f83cdd2de30ccf597fadd8418853954d1ce..f079e5a9aa098225acf09ed9b4aa7ddbc2381270 100644 ---- a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java -@@ -141,6 +141,7 @@ public class TripWireBlock extends Block { - - @Override - 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 (!world.isClientSide) { - if (!(Boolean) state.getValue(TripWireBlock.POWERED)) { - this.checkPressed(world, pos, List.of(entity)); -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 34599b88011aff718f5a6373229489ea3d947ff7..674d710ff88db5eced9e017284d1b7ec7a4fe7cd 100644 ---- a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java -@@ -33,6 +33,7 @@ public class WaterlilyBlock extends BushBlock { - - @Override - 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 - super.entityInside(state, world, pos, entity); - if (world instanceof ServerLevel && entity instanceof AbstractBoat) { - // CraftBukkit start -diff --git a/src/main/java/net/minecraft/world/level/block/WebBlock.java b/src/main/java/net/minecraft/world/level/block/WebBlock.java -index 4b621793da3d6fbc44f90df863b099ba992930fb..fc209fab3ed1ccb35706a5529ec23ad8b902e491 100644 ---- a/src/main/java/net/minecraft/world/level/block/WebBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/WebBlock.java -@@ -24,6 +24,7 @@ public class WebBlock extends Block { - - @Override - 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 - Vec3 vec3 = new Vec3(0.25, 0.05F, 0.25); - if (entity instanceof LivingEntity livingEntity && livingEntity.hasEffect(MobEffects.WEAVING)) { - vec3 = new Vec3(0.5, 0.25, 0.5); -diff --git a/src/main/java/net/minecraft/world/level/block/WitherRoseBlock.java b/src/main/java/net/minecraft/world/level/block/WitherRoseBlock.java -index b42924ebdd0f5369151b8a37f0070dec7f402073..8b79b2b7766d873b7e689309d936982fc1724686 100644 ---- a/src/main/java/net/minecraft/world/level/block/WitherRoseBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/WitherRoseBlock.java -@@ -63,6 +63,7 @@ public class WitherRoseBlock extends FlowerBlock { - - @Override - 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 (world instanceof ServerLevel worldserver) { - if (world.getDifficulty() != Difficulty.PEACEFUL && entity instanceof LivingEntity entityliving) { - if (!entityliving.isInvulnerableTo(worldserver, world.damageSources().wither())) { diff --git a/patches/server/0531-Improve-item-default-attribute-API.patch b/patches/server/0531-Improve-item-default-attribute-API.patch new file mode 100644 index 0000000000..4ded5398f8 --- /dev/null +++ b/patches/server/0531-Improve-item-default-attribute-API.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 8 May 2021 15:01:54 -0700 +Subject: [PATCH] Improve item default attribute API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java +index de0eba19c0c963adb4f17cea22333240021fd801..3b171a08bd0bedfe224905feb5838d2540199bce 100644 +--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java +@@ -75,7 +75,7 @@ public class CraftAttributeInstance implements AttributeInstance { + return new AttributeModifier(CraftNamespacedKey.fromMinecraft(nms.id()), nms.amount(), AttributeModifier.Operation.values()[nms.operation().ordinal()], org.bukkit.inventory.EquipmentSlotGroup.ANY); + } + +- public static AttributeModifier convert(net.minecraft.world.entity.ai.attributes.AttributeModifier nms, EquipmentSlot slot) { +- return new AttributeModifier(CraftNamespacedKey.fromMinecraft(nms.id()), nms.amount(), AttributeModifier.Operation.values()[nms.operation().ordinal()], slot.getGroup()); ++ public static AttributeModifier convert(net.minecraft.world.entity.ai.attributes.AttributeModifier nms, net.minecraft.world.entity.EquipmentSlotGroup slot) { // Paper ++ return new AttributeModifier(CraftNamespacedKey.fromMinecraft(nms.id()), nms.amount(), AttributeModifier.Operation.values()[nms.operation().ordinal()], org.bukkit.craftbukkit.CraftEquipmentSlot.getSlot(slot)); // Paper + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java +index 68756419ac6ee292db9569eab380a5c14d748002..6d76cc1db3ac3f1ae74c13511937fb86082a0b3d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java +@@ -197,16 +197,33 @@ public class CraftItemType implements ItemType.Typed, Han + // return CraftEquipmentSlot.getSlot(EntityInsentient.getEquipmentSlotForItem(CraftItemStack.asNMSCopy(ItemStack.of(this)))); + // } + ++ // Paper start - improve default attribute API ++ @Override ++ public @NotNull Multimap getDefaultAttributeModifiers() { ++ return this.getDefaultAttributeModifiers(sg -> true); ++ } ++ // Paper end - improve default attribute API ++ + @Override + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot) { ++ // Paper start - improve/fix item default attribute API ++ final net.minecraft.world.entity.EquipmentSlot nmsSlot = CraftEquipmentSlot.getNMS(slot); ++ return this.getDefaultAttributeModifiers(sg -> sg.test(nmsSlot)); ++ } ++ ++ private Multimap getDefaultAttributeModifiers(final java.util.function.Predicate slotPredicate) { ++ // Paper end - improve/fix item default attribute API + ImmutableMultimap.Builder defaultAttributes = ImmutableMultimap.builder(); + + ItemAttributeModifiers nmsDefaultAttributes = this.item.components().getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY); +- +- nmsDefaultAttributes.forEach(CraftEquipmentSlot.getNMS(slot), (key, value) -> { +- Attribute attribute = CraftAttribute.minecraftToBukkit(key.value()); +- defaultAttributes.put(attribute, CraftAttributeInstance.convert(value, slot)); +- }); ++ // Paper start - improve/fix item default attribute API ++ for (final net.minecraft.world.item.component.ItemAttributeModifiers.Entry entry : nmsDefaultAttributes.modifiers()) { ++ if (!slotPredicate.test(entry.slot())) continue; ++ final Attribute attribute = CraftAttribute.minecraftHolderToBukkit(entry.attribute()); ++ final AttributeModifier modifier = CraftAttributeInstance.convert(entry.modifier(), entry.slot()); ++ defaultAttributes.put(attribute, modifier); ++ } ++ // Paper end - improve/fix item default attribute API + + return defaultAttributes.build(); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index fa4e8cb2d53e0ac4e15a8188454ceed0afafe503..e613ea0eba9a1d162b8f7dfe32c9c31d82f17dd2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -386,7 +386,11 @@ public final class CraftMagicNumbers implements UnsafeValues { + + @Override + public Multimap getDefaultAttributeModifiers(Material material, EquipmentSlot slot) { +- return material.getDefaultAttributeModifiers(slot); ++ // Paper start - delegate to method on ItemType ++ final org.bukkit.inventory.ItemType item = material.asItemType(); ++ Preconditions.checkArgument(item != null, material + " is not an item and does not have default attributes"); ++ return item.getDefaultAttributeModifiers(slot); ++ // Paper end - delegate to method on ItemType + } + + @Override diff --git a/patches/server/0532-Add-cause-to-Weather-ThunderChangeEvents.patch b/patches/server/0532-Add-cause-to-Weather-ThunderChangeEvents.patch new file mode 100644 index 0000000000..41b63decc5 --- /dev/null +++ b/patches/server/0532-Add-cause-to-Weather-ThunderChangeEvents.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Dec 2020 18:23:26 -0800 +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 4f2d1a70007cd0a30567886e970bbfda6d750488..4982cdfbceb829e06f26eb927e1176bb4a975336 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -435,8 +435,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.serverLevelData.setClearWeatherTime(clearDuration); + this.serverLevelData.setRainTime(rainDuration); + this.serverLevelData.setThunderTime(rainDuration); +- this.serverLevelData.setRaining(raining); +- this.serverLevelData.setThundering(thundering); ++ this.serverLevelData.setRaining(raining, org.bukkit.event.weather.WeatherChangeEvent.Cause.COMMAND); // Paper - Add cause to Weather/ThunderChangeEvents ++ this.serverLevelData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.COMMAND); // Paper - Add cause to Weather/ThunderChangeEvents + } + + @Override +@@ -852,8 +852,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.serverLevelData.setThunderTime(j); + this.serverLevelData.setRainTime(k); + this.serverLevelData.setClearWeatherTime(i); +- this.serverLevelData.setThundering(flag1); +- this.serverLevelData.setRaining(flag2); ++ this.serverLevelData.setThundering(flag1, org.bukkit.event.weather.ThunderChangeEvent.Cause.NATURAL); // Paper - Add cause to Weather/ThunderChangeEvents ++ this.serverLevelData.setRaining(flag2, org.bukkit.event.weather.WeatherChangeEvent.Cause.NATURAL); // Paper - Add cause to Weather/ThunderChangeEvents + } + + this.oThunderLevel = this.thunderLevel; +@@ -920,14 +920,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + @VisibleForTesting + public void resetWeatherCycle() { + // CraftBukkit start +- this.serverLevelData.setRaining(false); ++ this.serverLevelData.setRaining(false, org.bukkit.event.weather.WeatherChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents + // If we stop due to everyone sleeping we should reset the weather duration to some other random value. + // Not that everyone ever manages to get the whole server to sleep at the same time.... + if (!this.serverLevelData.isRaining()) { + this.serverLevelData.setRainTime(0); + } + // CraftBukkit end +- this.serverLevelData.setThundering(false); ++ this.serverLevelData.setThundering(false, org.bukkit.event.weather.ThunderChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents + // CraftBukkit start + // If we stop due to everyone sleeping we should reset the weather duration to some other random value. + // Not that everyone ever manages to get the whole server to sleep at the same time.... +diff --git a/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java b/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java +index 6a3959095e57f76b3a092b32d26ff91cf1c5e068..0fa16ff37f09ecfda104b751e48bf246820afc98 100644 +--- a/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java ++++ b/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java +@@ -337,6 +337,11 @@ public class PrimaryLevelData implements ServerLevelData, WorldData { + + @Override + public void setThundering(boolean thundering) { ++ // Paper start - Add cause to Weather/ThunderChangeEvents ++ this.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.UNKNOWN); ++ } ++ public void setThundering(boolean thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause cause) { ++ // Paper end - Add cause to Weather/ThunderChangeEvents + // CraftBukkit start + if (this.thundering == thundering) { + return; +@@ -344,7 +349,7 @@ public class PrimaryLevelData implements ServerLevelData, WorldData { + + org.bukkit.World world = Bukkit.getWorld(this.getLevelName()); + if (world != null) { +- ThunderChangeEvent thunder = new ThunderChangeEvent(world, thundering); ++ ThunderChangeEvent thunder = new ThunderChangeEvent(world, thundering, cause); // Paper - Add cause to Weather/ThunderChangeEvents + Bukkit.getServer().getPluginManager().callEvent(thunder); + if (thunder.isCancelled()) { + return; +@@ -371,6 +376,12 @@ public class PrimaryLevelData implements ServerLevelData, WorldData { + + @Override + public void setRaining(boolean raining) { ++ // Paper start - Add cause to Weather/ThunderChangeEvents ++ this.setRaining(raining, org.bukkit.event.weather.WeatherChangeEvent.Cause.UNKNOWN); ++ } ++ ++ public void setRaining(boolean raining, org.bukkit.event.weather.WeatherChangeEvent.Cause cause) { ++ // Paper end - Add cause to Weather/ThunderChangeEvents + // CraftBukkit start + if (this.raining == raining) { + return; +@@ -378,7 +389,7 @@ public class PrimaryLevelData implements ServerLevelData, WorldData { + + org.bukkit.World world = Bukkit.getWorld(this.getLevelName()); + if (world != null) { +- WeatherChangeEvent weather = new WeatherChangeEvent(world, raining); ++ WeatherChangeEvent weather = new WeatherChangeEvent(world, raining, cause); // Paper - Add cause to Weather/ThunderChangeEvents + Bukkit.getServer().getPluginManager().callEvent(weather); + if (weather.isCancelled()) { + return; +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index f20717ee4505d28fa44f0f9ced5c71ae75c8a6d9..691d65bca79d503a43f696d92a0a32226cddaad5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1201,7 +1201,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setStorm(boolean hasStorm) { +- this.world.levelData.setRaining(hasStorm); ++ this.world.serverLevelData.setRaining(hasStorm, org.bukkit.event.weather.WeatherChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents + this.setWeatherDuration(0); // Reset weather duration (legacy behaviour) + this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) + } +@@ -1223,7 +1223,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setThundering(boolean thundering) { +- this.world.serverLevelData.setThundering(thundering); ++ this.world.serverLevelData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents + this.setThunderDuration(0); // Reset weather duration (legacy behaviour) + this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) + } diff --git a/patches/server/0532-Improve-item-default-attribute-API.patch b/patches/server/0532-Improve-item-default-attribute-API.patch deleted file mode 100644 index 4ded5398f8..0000000000 --- a/patches/server/0532-Improve-item-default-attribute-API.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 8 May 2021 15:01:54 -0700 -Subject: [PATCH] Improve item default attribute API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java -index de0eba19c0c963adb4f17cea22333240021fd801..3b171a08bd0bedfe224905feb5838d2540199bce 100644 ---- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java -@@ -75,7 +75,7 @@ public class CraftAttributeInstance implements AttributeInstance { - return new AttributeModifier(CraftNamespacedKey.fromMinecraft(nms.id()), nms.amount(), AttributeModifier.Operation.values()[nms.operation().ordinal()], org.bukkit.inventory.EquipmentSlotGroup.ANY); - } - -- public static AttributeModifier convert(net.minecraft.world.entity.ai.attributes.AttributeModifier nms, EquipmentSlot slot) { -- return new AttributeModifier(CraftNamespacedKey.fromMinecraft(nms.id()), nms.amount(), AttributeModifier.Operation.values()[nms.operation().ordinal()], slot.getGroup()); -+ public static AttributeModifier convert(net.minecraft.world.entity.ai.attributes.AttributeModifier nms, net.minecraft.world.entity.EquipmentSlotGroup slot) { // Paper -+ return new AttributeModifier(CraftNamespacedKey.fromMinecraft(nms.id()), nms.amount(), AttributeModifier.Operation.values()[nms.operation().ordinal()], org.bukkit.craftbukkit.CraftEquipmentSlot.getSlot(slot)); // Paper - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -index 68756419ac6ee292db9569eab380a5c14d748002..6d76cc1db3ac3f1ae74c13511937fb86082a0b3d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -@@ -197,16 +197,33 @@ public class CraftItemType implements ItemType.Typed, Han - // return CraftEquipmentSlot.getSlot(EntityInsentient.getEquipmentSlotForItem(CraftItemStack.asNMSCopy(ItemStack.of(this)))); - // } - -+ // Paper start - improve default attribute API -+ @Override -+ public @NotNull Multimap getDefaultAttributeModifiers() { -+ return this.getDefaultAttributeModifiers(sg -> true); -+ } -+ // Paper end - improve default attribute API -+ - @Override - public Multimap getDefaultAttributeModifiers(EquipmentSlot slot) { -+ // Paper start - improve/fix item default attribute API -+ final net.minecraft.world.entity.EquipmentSlot nmsSlot = CraftEquipmentSlot.getNMS(slot); -+ return this.getDefaultAttributeModifiers(sg -> sg.test(nmsSlot)); -+ } -+ -+ private Multimap getDefaultAttributeModifiers(final java.util.function.Predicate slotPredicate) { -+ // Paper end - improve/fix item default attribute API - ImmutableMultimap.Builder defaultAttributes = ImmutableMultimap.builder(); - - ItemAttributeModifiers nmsDefaultAttributes = this.item.components().getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY); -- -- nmsDefaultAttributes.forEach(CraftEquipmentSlot.getNMS(slot), (key, value) -> { -- Attribute attribute = CraftAttribute.minecraftToBukkit(key.value()); -- defaultAttributes.put(attribute, CraftAttributeInstance.convert(value, slot)); -- }); -+ // Paper start - improve/fix item default attribute API -+ for (final net.minecraft.world.item.component.ItemAttributeModifiers.Entry entry : nmsDefaultAttributes.modifiers()) { -+ if (!slotPredicate.test(entry.slot())) continue; -+ final Attribute attribute = CraftAttribute.minecraftHolderToBukkit(entry.attribute()); -+ final AttributeModifier modifier = CraftAttributeInstance.convert(entry.modifier(), entry.slot()); -+ defaultAttributes.put(attribute, modifier); -+ } -+ // Paper end - improve/fix item default attribute API - - return defaultAttributes.build(); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index fa4e8cb2d53e0ac4e15a8188454ceed0afafe503..e613ea0eba9a1d162b8f7dfe32c9c31d82f17dd2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -386,7 +386,11 @@ public final class CraftMagicNumbers implements UnsafeValues { - - @Override - public Multimap getDefaultAttributeModifiers(Material material, EquipmentSlot slot) { -- return material.getDefaultAttributeModifiers(slot); -+ // Paper start - delegate to method on ItemType -+ final org.bukkit.inventory.ItemType item = material.asItemType(); -+ Preconditions.checkArgument(item != null, material + " is not an item and does not have default attributes"); -+ return item.getDefaultAttributeModifiers(slot); -+ // Paper end - delegate to method on ItemType - } - - @Override diff --git a/patches/server/0533-Add-cause-to-Weather-ThunderChangeEvents.patch b/patches/server/0533-Add-cause-to-Weather-ThunderChangeEvents.patch deleted file mode 100644 index 6293b65e40..0000000000 --- a/patches/server/0533-Add-cause-to-Weather-ThunderChangeEvents.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 2 Dec 2020 18:23:26 -0800 -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 dc2b8d8e62cf1405191aa4fc8d4fa548c7249032..c05ccab70bd81d536f93352f30aab9b07b90876a 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -435,8 +435,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.serverLevelData.setClearWeatherTime(clearDuration); - this.serverLevelData.setRainTime(rainDuration); - this.serverLevelData.setThunderTime(rainDuration); -- this.serverLevelData.setRaining(raining); -- this.serverLevelData.setThundering(thundering); -+ this.serverLevelData.setRaining(raining, org.bukkit.event.weather.WeatherChangeEvent.Cause.COMMAND); // Paper - Add cause to Weather/ThunderChangeEvents -+ this.serverLevelData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.COMMAND); // Paper - Add cause to Weather/ThunderChangeEvents - } - - @Override -@@ -852,8 +852,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.serverLevelData.setThunderTime(j); - this.serverLevelData.setRainTime(k); - this.serverLevelData.setClearWeatherTime(i); -- this.serverLevelData.setThundering(flag1); -- this.serverLevelData.setRaining(flag2); -+ this.serverLevelData.setThundering(flag1, org.bukkit.event.weather.ThunderChangeEvent.Cause.NATURAL); // Paper - Add cause to Weather/ThunderChangeEvents -+ this.serverLevelData.setRaining(flag2, org.bukkit.event.weather.WeatherChangeEvent.Cause.NATURAL); // Paper - Add cause to Weather/ThunderChangeEvents - } - - this.oThunderLevel = this.thunderLevel; -@@ -920,14 +920,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - @VisibleForTesting - public void resetWeatherCycle() { - // CraftBukkit start -- this.serverLevelData.setRaining(false); -+ this.serverLevelData.setRaining(false, org.bukkit.event.weather.WeatherChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents - // If we stop due to everyone sleeping we should reset the weather duration to some other random value. - // Not that everyone ever manages to get the whole server to sleep at the same time.... - if (!this.serverLevelData.isRaining()) { - this.serverLevelData.setRainTime(0); - } - // CraftBukkit end -- this.serverLevelData.setThundering(false); -+ this.serverLevelData.setThundering(false, org.bukkit.event.weather.ThunderChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents - // CraftBukkit start - // If we stop due to everyone sleeping we should reset the weather duration to some other random value. - // Not that everyone ever manages to get the whole server to sleep at the same time.... -diff --git a/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java b/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java -index 6a3959095e57f76b3a092b32d26ff91cf1c5e068..0fa16ff37f09ecfda104b751e48bf246820afc98 100644 ---- a/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java -+++ b/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java -@@ -337,6 +337,11 @@ public class PrimaryLevelData implements ServerLevelData, WorldData { - - @Override - public void setThundering(boolean thundering) { -+ // Paper start - Add cause to Weather/ThunderChangeEvents -+ this.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.UNKNOWN); -+ } -+ public void setThundering(boolean thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause cause) { -+ // Paper end - Add cause to Weather/ThunderChangeEvents - // CraftBukkit start - if (this.thundering == thundering) { - return; -@@ -344,7 +349,7 @@ public class PrimaryLevelData implements ServerLevelData, WorldData { - - org.bukkit.World world = Bukkit.getWorld(this.getLevelName()); - if (world != null) { -- ThunderChangeEvent thunder = new ThunderChangeEvent(world, thundering); -+ ThunderChangeEvent thunder = new ThunderChangeEvent(world, thundering, cause); // Paper - Add cause to Weather/ThunderChangeEvents - Bukkit.getServer().getPluginManager().callEvent(thunder); - if (thunder.isCancelled()) { - return; -@@ -371,6 +376,12 @@ public class PrimaryLevelData implements ServerLevelData, WorldData { - - @Override - public void setRaining(boolean raining) { -+ // Paper start - Add cause to Weather/ThunderChangeEvents -+ this.setRaining(raining, org.bukkit.event.weather.WeatherChangeEvent.Cause.UNKNOWN); -+ } -+ -+ public void setRaining(boolean raining, org.bukkit.event.weather.WeatherChangeEvent.Cause cause) { -+ // Paper end - Add cause to Weather/ThunderChangeEvents - // CraftBukkit start - if (this.raining == raining) { - return; -@@ -378,7 +389,7 @@ public class PrimaryLevelData implements ServerLevelData, WorldData { - - org.bukkit.World world = Bukkit.getWorld(this.getLevelName()); - if (world != null) { -- WeatherChangeEvent weather = new WeatherChangeEvent(world, raining); -+ WeatherChangeEvent weather = new WeatherChangeEvent(world, raining, cause); // Paper - Add cause to Weather/ThunderChangeEvents - Bukkit.getServer().getPluginManager().callEvent(weather); - if (weather.isCancelled()) { - return; -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index f20717ee4505d28fa44f0f9ced5c71ae75c8a6d9..691d65bca79d503a43f696d92a0a32226cddaad5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1201,7 +1201,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setStorm(boolean hasStorm) { -- this.world.levelData.setRaining(hasStorm); -+ this.world.serverLevelData.setRaining(hasStorm, org.bukkit.event.weather.WeatherChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents - this.setWeatherDuration(0); // Reset weather duration (legacy behaviour) - this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) - } -@@ -1223,7 +1223,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setThundering(boolean thundering) { -- this.world.serverLevelData.setThundering(thundering); -+ this.world.serverLevelData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents - this.setThunderDuration(0); // Reset weather duration (legacy behaviour) - this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) - } diff --git a/patches/server/0533-More-Lidded-Block-API.patch b/patches/server/0533-More-Lidded-Block-API.patch new file mode 100644 index 0000000000..437434c525 --- /dev/null +++ b/patches/server/0533-More-Lidded-Block-API.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: LemonCaramel +Date: Sun, 23 May 2021 17:49:51 +0900 +Subject: [PATCH] More Lidded Block API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBarrel.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBarrel.java +index f4b480e3041fc79060c5fa6ce517047104b280d5..6063f0e1fdc232d063105971359ae688168a2bc4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBarrel.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBarrel.java +@@ -73,4 +73,11 @@ public class CraftBarrel extends CraftLootable implements Bar + public CraftBarrel copy(Location location) { + return new CraftBarrel(this, location); + } ++ ++ // Paper start - More Lidded Block API ++ @Override ++ public boolean isOpen() { ++ return getTileEntity().openersCounter.opened; ++ } ++ // Paper end - More Lidded Block API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +index 2b6a93a944b27290745278957a3577772b7b8212..6e98a00d526b734992ce39b15768c5820dce4ca8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +@@ -92,4 +92,11 @@ public class CraftChest extends CraftLootable implements Chest + public CraftChest copy(Location location) { + return new CraftChest(this, location); + } ++ ++ // Paper start - More Lidded Block API ++ @Override ++ public boolean isOpen() { ++ return getTileEntity().openersCounter.opened; ++ } ++ // Paper end - More Lidded 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 07b63ce5f5e152f6a644134989ffa03af8a12cdf..b64adbba3e52d32d439e64a243cb74f3fbca2ce3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java +@@ -51,4 +51,11 @@ public class CraftEnderChest extends CraftBlockEntityState implem + if (this.getTileEntity().opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level) { + net.minecraft.world.level.Level world = this.getTileEntity().getLevel(); + world.blockEvent(this.getPosition(), this.getTileEntity().getBlockState().getBlock(), 1, 0); +- world.playSound(null, this.getPosition(), SoundEvents.SHULKER_BOX_OPEN, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); ++ world.playSound(null, this.getPosition(), SoundEvents.SHULKER_BOX_CLOSE, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); // Paper - More Lidded Block API (Wrong sound) + } + this.getTileEntity().opened = false; + } +@@ -73,4 +73,11 @@ public class CraftShulkerBox extends CraftLootable implem + public CraftShulkerBox copy(Location location) { + return new CraftShulkerBox(this, location); + } ++ ++ // Paper start - More Lidded Block API ++ @Override ++ public boolean isOpen() { ++ return getTileEntity().opened; ++ } ++ // Paper end - More Lidded Block API + } diff --git a/patches/server/0534-Limit-item-frame-cursors-on-maps.patch b/patches/server/0534-Limit-item-frame-cursors-on-maps.patch new file mode 100644 index 0000000000..a55a4490c0 --- /dev/null +++ b/patches/server/0534-Limit-item-frame-cursors-on-maps.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yive +Date: Wed, 26 May 2021 15:09:33 -0700 +Subject: [PATCH] Limit item frame cursors on maps + + +diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +index a89f0b652c515efbc24ffc9af47fa65082946e54..2d5e7380e8a14cbc01ba48cd05deccc0c7f53430 100644 +--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java ++++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +@@ -326,8 +326,10 @@ public class MapItemSavedData extends SavedData { + + MapFrame worldmapframe1 = new MapFrame(blockposition, entityitemframe.getDirection().get2DDataValue() * 90, entityitemframe.getId()); + ++ if (this.decorations.size() < player.level().paperConfig().maps.itemFrameCursorLimit) { // Paper - Limit item frame cursors on maps + this.addDecoration(MapDecorationTypes.FRAME, player.level(), MapItemSavedData.getFrameKey(entityitemframe.getId()), (double) blockposition.getX(), (double) blockposition.getZ(), (double) (entityitemframe.getDirection().get2DDataValue() * 90), (Component) null); + this.frameMarkers.put(worldmapframe1.getId(), worldmapframe1); ++ } // Paper - Limit item frame cursors on maps + } + + MapDecorations mapdecorations = (MapDecorations) stack.getOrDefault(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY); +@@ -520,7 +522,7 @@ public class MapItemSavedData extends SavedData { + return true; + } + +- if (!this.isTrackedCountOverLimit(256)) { ++ if (!this.isTrackedCountOverLimit(((Level) world).paperConfig().maps.itemFrameCursorLimit)) { // Paper - Limit item frame cursors on maps + this.bannerMarkers.put(mapiconbanner.getId(), mapiconbanner); + this.addDecoration(mapiconbanner.getDecoration(), world, mapiconbanner.getId(), d0, d1, 180.0D, (Component) mapiconbanner.name().orElse(null)); // CraftBukkit - decompile error + return true; diff --git a/patches/server/0534-More-Lidded-Block-API.patch b/patches/server/0534-More-Lidded-Block-API.patch deleted file mode 100644 index 437434c525..0000000000 --- a/patches/server/0534-More-Lidded-Block-API.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: LemonCaramel -Date: Sun, 23 May 2021 17:49:51 +0900 -Subject: [PATCH] More Lidded Block API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBarrel.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBarrel.java -index f4b480e3041fc79060c5fa6ce517047104b280d5..6063f0e1fdc232d063105971359ae688168a2bc4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBarrel.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBarrel.java -@@ -73,4 +73,11 @@ public class CraftBarrel extends CraftLootable implements Bar - public CraftBarrel copy(Location location) { - return new CraftBarrel(this, location); - } -+ -+ // Paper start - More Lidded Block API -+ @Override -+ public boolean isOpen() { -+ return getTileEntity().openersCounter.opened; -+ } -+ // Paper end - More Lidded Block API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java -index 2b6a93a944b27290745278957a3577772b7b8212..6e98a00d526b734992ce39b15768c5820dce4ca8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java -@@ -92,4 +92,11 @@ public class CraftChest extends CraftLootable implements Chest - public CraftChest copy(Location location) { - return new CraftChest(this, location); - } -+ -+ // Paper start - More Lidded Block API -+ @Override -+ public boolean isOpen() { -+ return getTileEntity().openersCounter.opened; -+ } -+ // Paper end - More Lidded 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 07b63ce5f5e152f6a644134989ffa03af8a12cdf..b64adbba3e52d32d439e64a243cb74f3fbca2ce3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java -@@ -51,4 +51,11 @@ public class CraftEnderChest extends CraftBlockEntityState implem - if (this.getTileEntity().opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level) { - net.minecraft.world.level.Level world = this.getTileEntity().getLevel(); - world.blockEvent(this.getPosition(), this.getTileEntity().getBlockState().getBlock(), 1, 0); -- world.playSound(null, this.getPosition(), SoundEvents.SHULKER_BOX_OPEN, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); -+ world.playSound(null, this.getPosition(), SoundEvents.SHULKER_BOX_CLOSE, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); // Paper - More Lidded Block API (Wrong sound) - } - this.getTileEntity().opened = false; - } -@@ -73,4 +73,11 @@ public class CraftShulkerBox extends CraftLootable implem - public CraftShulkerBox copy(Location location) { - return new CraftShulkerBox(this, location); - } -+ -+ // Paper start - More Lidded Block API -+ @Override -+ public boolean isOpen() { -+ return getTileEntity().opened; -+ } -+ // Paper end - More Lidded Block API - } diff --git a/patches/server/0535-Add-PlayerKickEvent-causes.patch b/patches/server/0535-Add-PlayerKickEvent-causes.patch new file mode 100644 index 0000000000..3cf5bd7d58 --- /dev/null +++ b/patches/server/0535-Add-PlayerKickEvent-causes.patch @@ -0,0 +1,548 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 15 May 2021 20:30:45 -0700 +Subject: [PATCH] Add PlayerKickEvent causes + + +diff --git a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java +index dbcf183483766f39334d7f7e8336033906625f3f..300929a406905f5ff1ede664d5b99fb0938d4d2e 100644 +--- a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java ++++ b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java +@@ -40,14 +40,14 @@ public class SignedMessageChain { + if (signature == null) { + throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.MISSING_PROFILE_KEY); + } else if (playerPublicKey.data().hasExpired()) { +- throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.EXPIRED_PROFILE_KEY); ++ throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.EXPIRED_PROFILE_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes + } else { + SignedMessageLink signedMessageLink = SignedMessageChain.this.nextLink; + if (signedMessageLink == null) { + throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.CHAIN_BROKEN); + } else if (body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) { + this.setChainBroken(); +- throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT); ++ throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes + } else { + SignedMessageChain.this.lastTimeStamp = body.timeStamp(); + PlayerChatMessage playerChatMessage = new PlayerChatMessage(signedMessageLink, signature, body, null, FilterMask.PASS_THROUGH); +@@ -80,8 +80,15 @@ public class SignedMessageChain { + static final Component INVALID_SIGNATURE = Component.translatable("chat.disabled.invalid_signature"); + static final Component OUT_OF_ORDER_CHAT = Component.translatable("chat.disabled.out_of_order_chat"); + +- public DecodeException(Component message) { ++ // Paper start ++ public final org.bukkit.event.player.PlayerKickEvent.Cause kickCause; ++ public DecodeException(Component message, org.bukkit.event.player.PlayerKickEvent.Cause event) { + super(message); ++ this.kickCause = event; ++ } ++ // Paper end ++ public DecodeException(Component message) { ++ this(message, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); // Paper + } + } + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 0ab92fb362729108beca6bc0230fb6fb06ca6280..edd2e83df282b0e24d4c7e3a34776a5b039c2c6b 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -2325,7 +2325,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop Component.translatable("commands.kick.success", serverPlayer.getDisplayName(), reason), true); + i++; + } +diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +index f8ae8c8eff73e4e87eb34d0f2635517f1688a6f1..59d20fd62e850a38380d877cef95ed69cb46ecbd 100644 +--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +@@ -63,8 +63,8 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + } + + @Override +- public void kickPlayer(Component reason) { +- this.disconnect(reason); ++ public void kickPlayer(Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { // Paper - kick event causes ++ this.disconnect(reason, cause); // Paper - kick event causes + } + // CraftBukkit end + private static final Logger LOGGER = LogUtils.getLogger(); +@@ -140,7 +140,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + } else if (!this.isSingleplayerOwner()) { + // Paper start - This needs to be handled on the main thread for plugins + server.submit(() -> { +- this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE); ++ this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause + }); + // Paper end - This needs to be handled on the main thread for plugins + } +@@ -176,7 +176,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + } + } catch (Exception ex) { + ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t register custom payload", ex); +- this.disconnect(Component.literal("Invalid payload REGISTER!")); ++ this.disconnect(Component.literal("Invalid payload REGISTER!"), PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause + } + } else if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_UNREGISTER)) { + try { +@@ -186,7 +186,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + } + } catch (Exception ex) { + ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t unregister custom payload", ex); +- this.disconnect(Component.literal("Invalid payload UNREGISTER!")); ++ this.disconnect(Component.literal("Invalid payload UNREGISTER!"), PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause + } + } else { + try { +@@ -204,7 +204,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), identifier.toString(), data); + } catch (Exception ex) { + ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t dispatch custom payload", ex); +- this.disconnect(Component.literal("Invalid custom payload!")); ++ this.disconnect(Component.literal("Invalid custom payload!"), PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause + } + } + +@@ -220,7 +220,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + PacketUtils.ensureRunningOnSameThread(packet, this, (BlockableEventLoop) this.server); + if (packet.action() == ServerboundResourcePackPacket.Action.DECLINED && this.server.isResourcePackRequired()) { + ServerCommonPacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack {} rejection", this.playerProfile().getName(), packet.id()); +- this.disconnect((Component) Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); ++ this.disconnect((Component) Component.translatable("multiplayer.requiredTexturePrompt.disconnect"), PlayerKickEvent.Cause.RESOURCE_PACK_REJECTION); // Paper - kick event cause + } + // Paper start - adventure pack callbacks + // call the callbacks before the previously-existing event so the event has final say +@@ -250,7 +250,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + return; + } + // CraftBukkit end +- this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY); ++ this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY, PlayerKickEvent.Cause.INVALID_COOKIE); // Paper - kick event cause + } + + protected void keepConnectionAlive() { +@@ -262,7 +262,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + + if (!this.isSingleplayerOwner() && elapsedTime >= 15000L) { // Paper - use vanilla's 15000L between keep alive packets + if (this.keepAlivePending && !this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // Paper - check keepalive limit, don't fire if already disconnected +- this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE); ++ this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause + } else if (this.checkIfClosed(currentTime)) { // Paper + this.keepAlivePending = true; + this.keepAliveTime = currentTime; +@@ -278,7 +278,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + private boolean checkIfClosed(long time) { + if (this.closed) { + if (time - this.closedListenerTime >= 15000L) { +- this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE); ++ this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause + } + + return false; +@@ -330,15 +330,25 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + + // Paper start - adventure + public void disconnect(final net.kyori.adventure.text.Component reason) { +- this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(reason)); ++ this.disconnect(reason, PlayerKickEvent.Cause.UNKNOWN); ++ } ++ public void disconnect(final net.kyori.adventure.text.Component reason, PlayerKickEvent.Cause cause) { ++ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(reason), cause); ++ // Paper end - kick event causes + } + // Paper end - adventure + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - kick event causes + public void disconnect(Component reason) { +- this.disconnect(new DisconnectionDetails(reason)); ++ // Paper start - kick event causes ++ this.disconnect(reason, PlayerKickEvent.Cause.UNKNOWN); ++ } ++ public void disconnect(final Component reason, PlayerKickEvent.Cause cause) { ++ this.disconnect(new DisconnectionDetails(reason), cause); ++ // Paper end - kick event causes + } + +- public void disconnect(DisconnectionDetails disconnectionInfo) { ++ public void disconnect(DisconnectionDetails disconnectionInfo, PlayerKickEvent.Cause cause) { // Paper - kick event cause + // CraftBukkit start - fire PlayerKickEvent + if (this.processedDisconnect) { + return; +@@ -347,7 +357,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + Waitable waitable = new Waitable() { + @Override + protected Object evaluate() { +- ServerCommonPacketListenerImpl.this.disconnect(disconnectionInfo); ++ ServerCommonPacketListenerImpl.this.disconnect(disconnectionInfo, cause); // Paper - kick event causes + return null; + } + }; +@@ -366,7 +376,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + + net.kyori.adventure.text.Component leaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? this.player.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(this.player.getScoreboardName())); // Paper - Adventure + +- PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(disconnectionInfo.reason()), leaveMessage); // Paper - adventure ++ PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(disconnectionInfo.reason()), leaveMessage, cause); // Paper - adventure & kick event causes + + if (this.cserver.getServer().isRunning()) { + this.cserver.getPluginManager().callEvent(event); +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 5e809ac566834307ced0c56727c42fc712f026df..8f1188bd5e9e1ae7e5318674038c2d7f87d743b7 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -361,7 +361,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger() && !this.player.isDeadOrDying()) { + if (++this.aboveGroundTickCount > this.getMaximumFlyingTicks(this.player)) { + ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating too long!", this.player.getName().getString()); +- this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer); // Paper - use configurable kick message ++ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_PLAYER); // Paper - use configurable kick message & kick event cause + return; + } + } else { +@@ -380,7 +380,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + if (this.clientVehicleIsFloating && this.lastVehicle.getControllingPassenger() == this.player) { + if (++this.aboveGroundVehicleTickCount > this.getMaximumFlyingTicks(this.lastVehicle)) { + ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating a vehicle too long!", this.player.getName().getString()); +- this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle); // Paper - use configurable kick message ++ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_VEHICLE); // Paper - use configurable kick message & kick event cause + return; + } + } else { +@@ -400,7 +400,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.dropSpamThrottler.tick(); + if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { + this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 +- this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling")); ++ this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause + } + + } +@@ -488,7 +488,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + public void handleMoveVehicle(ServerboundMoveVehiclePacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (ServerGamePacketListenerImpl.containsInvalidValues(packet.position().x(), packet.position().y(), packet.position().z(), packet.yRot(), packet.xRot())) { +- this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_vehicle_movement")); ++ 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() && this.player.hasClientLoaded()) { + Entity entity = this.player.getRootVehicle(); + +@@ -687,7 +687,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (packet.getId() == this.awaitingTeleport) { + if (this.awaitingPositionFromClient == null) { +- this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement")); ++ this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause + return; + } + +@@ -754,7 +754,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper - AsyncTabCompleteEvent; run this async + // CraftBukkit start + if (!this.tabSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { // Paper - configurable tab spam limits +- this.disconnect(Component.translatable("disconnect.spam")); ++ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause + return; + } + // CraftBukkit end +@@ -1178,14 +1178,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + if (byteTotal > byteAllowed) { + ServerGamePacketListenerImpl.LOGGER.warn("{} tried to send a book too large. Book size: {} - Allowed: {} - Pages: {}", this.player.getScoreboardName(), byteTotal, byteAllowed, pageList.size()); +- this.disconnect(Component.literal("Book too large!")); ++ this.disconnect(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause + return; + } + } + // Paper end - Book size limits + // CraftBukkit start + if (this.lastBookTick + 20 > MinecraftServer.currentTick) { +- this.disconnect(Component.literal("Book edited too quickly!")); ++ this.disconnect(Component.literal("Book edited too quickly!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause + return; + } + this.lastBookTick = MinecraftServer.currentTick; +@@ -1294,7 +1294,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + public void handleMovePlayer(ServerboundMovePlayerPacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (ServerGamePacketListenerImpl.containsInvalidValues(packet.getX(0.0D), packet.getY(0.0D), packet.getZ(0.0D), packet.getYRot(0.0F), packet.getXRot(0.0F))) { +- this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement")); ++ this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause + } else { + ServerLevel worldserver = this.player.serverLevel(); + +@@ -1734,7 +1734,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.dropCount++; + if (this.dropCount >= 20) { + ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " dropped their items too quickly!"); +- this.disconnect(Component.literal("You dropped your items too quickly (Hacking?)")); ++ this.disconnect(Component.literal("You dropped your items too quickly (Hacking?)"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause + return; + } + } +@@ -2036,7 +2036,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.player.resetLastActionTime(); + } else { + ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString()); +- this.disconnect(Component.literal("Invalid hotbar selection (Hacking?)")); // CraftBukkit ++ this.disconnect(Component.literal("Invalid hotbar selection (Hacking?)"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // CraftBukkit // Paper - kick event cause + } + } + +@@ -2234,7 +2234,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + private void tryHandleChat(String s, Runnable runnable, boolean sync) { // CraftBukkit + if (ServerGamePacketListenerImpl.isChatMessageIllegal(s)) { +- this.disconnect((Component) Component.translatable("multiplayer.disconnect.illegal_characters")); ++ this.disconnect((Component) Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper + } else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales + this.send(new ClientboundSystemChatPacket(Component.translatable("chat.disabled.options").withStyle(ChatFormatting.RED), false)); + } else { +@@ -2257,7 +2257,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + if (optional.isEmpty()) { + ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); +- this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED); ++ this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes + } + + return optional; +@@ -2438,7 +2438,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + // this.chatSpamThrottler.increment(); + if (!this.chatSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { + // CraftBukkit end +- this.disconnect((Component) Component.translatable("disconnect.spam")); ++ this.disconnect((Component) Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause + } + + } +@@ -2450,7 +2450,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + synchronized (this.lastSeenMessages) { + if (!this.lastSeenMessages.applyOffset(packet.offset())) { + ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); +- this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED); ++ this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes + } + + } +@@ -2603,7 +2603,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + + if (i > 4096) { +- this.disconnect((Component) Component.translatable("multiplayer.disconnect.too_many_pending_chats")); ++ this.disconnect((Component) Component.translatable("multiplayer.disconnect.too_many_pending_chats"), org.bukkit.event.player.PlayerKickEvent.Cause.TOO_MANY_PENDING_CHATS); // Paper - kick event cause + } + + } +@@ -2662,7 +2662,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + // Spigot Start + if ( entity == this.player && !this.player.isSpectator() ) + { +- this.disconnect( Component.literal( "Cannot interact with self!" ) ); ++ this.disconnect( Component.literal( "Cannot interact with self!" ), org.bukkit.event.player.PlayerKickEvent.Cause.SELF_INTERACTION ); // Paper - kick event cause + return; + } + // Spigot End +@@ -2778,7 +2778,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + } + +- ServerGamePacketListenerImpl.this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_entity_attacked")); ++ ServerGamePacketListenerImpl.this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_entity_attacked"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_ENTITY_ATTACKED); // Paper - add cause + ServerGamePacketListenerImpl.LOGGER.warn("Player {} tried to attack an invalid entity", ServerGamePacketListenerImpl.this.player.getName().getString()); + } + }); +@@ -3178,7 +3178,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + // Paper start - auto recipe limit + if (!org.bukkit.Bukkit.isPrimaryThread()) { + if (!this.recipeSpamPackets.isIncrementAndUnderThreshold()) { +- this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam")); ++ this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause + return; + } + } +@@ -3440,7 +3440,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + if (!Objects.equals(profilepublickey_a, profilepublickey_a1)) { + if (profilepublickey_a != null && profilepublickey_a1.expiresAt().isBefore(profilepublickey_a.expiresAt())) { +- this.disconnect(ProfilePublicKey.EXPIRED_PROFILE_PUBLIC_KEY); ++ this.disconnect(ProfilePublicKey.EXPIRED_PROFILE_PUBLIC_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes + } else { + try { + SignatureValidator signaturevalidator = this.server.getProfileKeySignatureValidator(); +@@ -3453,7 +3453,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()); +- this.disconnect(profilepublickey_b.getComponent()); ++ this.disconnect(profilepublickey_b.getComponent(), profilepublickey_b.kickCause); // Paper - kick event causes + } + + } +diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index 9d5723cdfdbf6257a71e57842aea9ba317fc049a..1e4b288f20153ce0c91fabf164c5c8320c90ba7d 100644 +--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +@@ -70,7 +70,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + } + + @Override +- public void kickPlayer(Component reason) { ++ public void kickPlayer(Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { // Paper - kick event causes - during login, no event can be called. + this.disconnect(reason); + } + // 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 ee6a3e8a8827468d787f5aa116d9876ae7654352..0dbbf067bab9f2ceb5994a1d9a411e2c1824ad16 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -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 +- entityplayer.connection.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login")); ++ entityplayer.connection.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login"), org.bukkit.event.player.PlayerKickEvent.Cause.DUPLICATE_LOGIN); // Paper - kick event cause + } + + // Instead of kicking then returning, we need to store the kick reason +@@ -1237,7 +1237,7 @@ public abstract class PlayerList { + // Paper end + // CraftBukkit start - disconnect safely + for (ServerPlayer player : this.players) { +- if (isRestarting) player.connection.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.restartMessage)); else // Paper ++ if (isRestarting) player.connection.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.restartMessage), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); else // Paper - kick event cause (cause is never used here) + player.connection.disconnect(java.util.Objects.requireNonNullElseGet(this.server.server.shutdownMessage(), net.kyori.adventure.text.Component::empty)); // CraftBukkit - add custom shutdown message // Paper - Adventure + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java b/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java +index 9e2ad78b12cadbf0e2bda1e12fe844120529c347..6a7d7fad990fc44fdda6849d43dad141e61f7f37 100644 +--- a/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java ++++ b/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java +@@ -24,7 +24,7 @@ public record ProfilePublicKey(ProfilePublicKey.Data data) { + + public static ProfilePublicKey createValidated(SignatureValidator servicesSignatureVerifier, UUID playerUuid, ProfilePublicKey.Data publicKeyData) throws ProfilePublicKey.ValidationException { + if (!publicKeyData.validateSignature(servicesSignatureVerifier, playerUuid)) { +- throw new ProfilePublicKey.ValidationException(INVALID_SIGNATURE); ++ throw new ProfilePublicKey.ValidationException(INVALID_SIGNATURE, org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PUBLIC_KEY_SIGNATURE); // Paper - kick event causes + } else { + return new ProfilePublicKey(publicKeyData); + } +@@ -88,8 +88,16 @@ public record ProfilePublicKey(ProfilePublicKey.Data data) { + } + + public static class ValidationException extends ThrowingComponent { ++ public final org.bukkit.event.player.PlayerKickEvent.Cause kickCause; // Paper ++ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper + public ValidationException(Component messageText) { ++ // Paper start ++ this(messageText, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); ++ } ++ public ValidationException(Component messageText, org.bukkit.event.player.PlayerKickEvent.Cause kickCause) { ++ // Paper end + super(messageText); ++ this.kickCause = kickCause; // Paper + } + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 0b151a66d7419653088526bd72119ebd2d6dd18e..ff8d6a0ceb41258541c0049464dc0923ed4872bd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -280,7 +280,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + void sendPacket(Packet packet); + +- void kickPlayer(Component reason); ++ void kickPlayer(Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause); // Paper - kick event causes + } + + public record CookieFuture(ResourceLocation key, CompletableFuture future) { +@@ -640,7 +640,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + @Override + public void kickPlayer(String message) { + org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot +- this.getHandle().transferCookieConnection.kickPlayer(CraftChatMessage.fromStringOrEmpty(message, true)); ++ this.getHandle().transferCookieConnection.kickPlayer(CraftChatMessage.fromStringOrEmpty(message, true), org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); // Paper - kick event cause + } + + // Paper start +@@ -652,10 +652,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + @Override + public void kick(final net.kyori.adventure.text.Component message) { ++ kick(message, org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); ++ } ++ ++ @Override ++ public void kick(net.kyori.adventure.text.Component message, org.bukkit.event.player.PlayerKickEvent.Cause cause) { + org.spigotmc.AsyncCatcher.catchOp("player kick"); + final ServerGamePacketListenerImpl connection = this.getHandle().connection; + if (connection != null) { +- connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message); ++ connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message, cause); + } + } + +@@ -716,7 +721,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + // Paper start - Improve chat handling + if (ServerGamePacketListenerImpl.isChatMessageIllegal(msg)) { +- this.getHandle().connection.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters")); ++ this.getHandle().connection.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - kick event causes + } else { + if (msg.startsWith("/")) { + this.getHandle().connection.handleCommand(msg); +diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java +index 824c4ad135ea5177f416687c7042639ed126b70b..39e56b95aaafbcd8ebe68fdefaace83702e9510d 100644 +--- a/src/main/java/org/spigotmc/RestartCommand.java ++++ b/src/main/java/org/spigotmc/RestartCommand.java +@@ -74,7 +74,7 @@ public class RestartCommand extends Command + // Kick all players + for ( ServerPlayer p : com.google.common.collect.ImmutableList.copyOf( MinecraftServer.getServer().getPlayerList().players ) ) + { +- p.connection.disconnect( CraftChatMessage.fromStringOrEmpty( SpigotConfig.restartMessage, true ) ); ++ p.connection.disconnect( CraftChatMessage.fromStringOrEmpty( SpigotConfig.restartMessage, true ), org.bukkit.event.player.PlayerKickEvent.Cause.RESTART_COMMAND); // Paper - kick event reason (cause is never used)) + } + // Give the socket a chance to send the packets + try diff --git a/patches/server/0535-Limit-item-frame-cursors-on-maps.patch b/patches/server/0535-Limit-item-frame-cursors-on-maps.patch deleted file mode 100644 index a55a4490c0..0000000000 --- a/patches/server/0535-Limit-item-frame-cursors-on-maps.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Yive -Date: Wed, 26 May 2021 15:09:33 -0700 -Subject: [PATCH] Limit item frame cursors on maps - - -diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -index a89f0b652c515efbc24ffc9af47fa65082946e54..2d5e7380e8a14cbc01ba48cd05deccc0c7f53430 100644 ---- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -326,8 +326,10 @@ public class MapItemSavedData extends SavedData { - - MapFrame worldmapframe1 = new MapFrame(blockposition, entityitemframe.getDirection().get2DDataValue() * 90, entityitemframe.getId()); - -+ if (this.decorations.size() < player.level().paperConfig().maps.itemFrameCursorLimit) { // Paper - Limit item frame cursors on maps - this.addDecoration(MapDecorationTypes.FRAME, player.level(), MapItemSavedData.getFrameKey(entityitemframe.getId()), (double) blockposition.getX(), (double) blockposition.getZ(), (double) (entityitemframe.getDirection().get2DDataValue() * 90), (Component) null); - this.frameMarkers.put(worldmapframe1.getId(), worldmapframe1); -+ } // Paper - Limit item frame cursors on maps - } - - MapDecorations mapdecorations = (MapDecorations) stack.getOrDefault(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY); -@@ -520,7 +522,7 @@ public class MapItemSavedData extends SavedData { - return true; - } - -- if (!this.isTrackedCountOverLimit(256)) { -+ if (!this.isTrackedCountOverLimit(((Level) world).paperConfig().maps.itemFrameCursorLimit)) { // Paper - Limit item frame cursors on maps - this.bannerMarkers.put(mapiconbanner.getId(), mapiconbanner); - this.addDecoration(mapiconbanner.getDecoration(), world, mapiconbanner.getId(), d0, d1, 180.0D, (Component) mapiconbanner.name().orElse(null)); // CraftBukkit - decompile error - return true; diff --git a/patches/server/0536-Add-PlayerKickEvent-causes.patch b/patches/server/0536-Add-PlayerKickEvent-causes.patch deleted file mode 100644 index 3cf5bd7d58..0000000000 --- a/patches/server/0536-Add-PlayerKickEvent-causes.patch +++ /dev/null @@ -1,548 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 15 May 2021 20:30:45 -0700 -Subject: [PATCH] Add PlayerKickEvent causes - - -diff --git a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java -index dbcf183483766f39334d7f7e8336033906625f3f..300929a406905f5ff1ede664d5b99fb0938d4d2e 100644 ---- a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java -+++ b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java -@@ -40,14 +40,14 @@ public class SignedMessageChain { - if (signature == null) { - throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.MISSING_PROFILE_KEY); - } else if (playerPublicKey.data().hasExpired()) { -- throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.EXPIRED_PROFILE_KEY); -+ throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.EXPIRED_PROFILE_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes - } else { - SignedMessageLink signedMessageLink = SignedMessageChain.this.nextLink; - if (signedMessageLink == null) { - throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.CHAIN_BROKEN); - } else if (body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) { - this.setChainBroken(); -- throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT); -+ throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes - } else { - SignedMessageChain.this.lastTimeStamp = body.timeStamp(); - PlayerChatMessage playerChatMessage = new PlayerChatMessage(signedMessageLink, signature, body, null, FilterMask.PASS_THROUGH); -@@ -80,8 +80,15 @@ public class SignedMessageChain { - static final Component INVALID_SIGNATURE = Component.translatable("chat.disabled.invalid_signature"); - static final Component OUT_OF_ORDER_CHAT = Component.translatable("chat.disabled.out_of_order_chat"); - -- public DecodeException(Component message) { -+ // Paper start -+ public final org.bukkit.event.player.PlayerKickEvent.Cause kickCause; -+ public DecodeException(Component message, org.bukkit.event.player.PlayerKickEvent.Cause event) { - super(message); -+ this.kickCause = event; -+ } -+ // Paper end -+ public DecodeException(Component message) { -+ this(message, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); // Paper - } - } - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 0ab92fb362729108beca6bc0230fb6fb06ca6280..edd2e83df282b0e24d4c7e3a34776a5b039c2c6b 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2325,7 +2325,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop Component.translatable("commands.kick.success", serverPlayer.getDisplayName(), reason), true); - i++; - } -diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index f8ae8c8eff73e4e87eb34d0f2635517f1688a6f1..59d20fd62e850a38380d877cef95ed69cb46ecbd 100644 ---- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -63,8 +63,8 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - } - - @Override -- public void kickPlayer(Component reason) { -- this.disconnect(reason); -+ public void kickPlayer(Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { // Paper - kick event causes -+ this.disconnect(reason, cause); // Paper - kick event causes - } - // CraftBukkit end - private static final Logger LOGGER = LogUtils.getLogger(); -@@ -140,7 +140,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - } else if (!this.isSingleplayerOwner()) { - // Paper start - This needs to be handled on the main thread for plugins - server.submit(() -> { -- this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE); -+ this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause - }); - // Paper end - This needs to be handled on the main thread for plugins - } -@@ -176,7 +176,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - } - } catch (Exception ex) { - ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t register custom payload", ex); -- this.disconnect(Component.literal("Invalid payload REGISTER!")); -+ this.disconnect(Component.literal("Invalid payload REGISTER!"), PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause - } - } else if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_UNREGISTER)) { - try { -@@ -186,7 +186,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - } - } catch (Exception ex) { - ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t unregister custom payload", ex); -- this.disconnect(Component.literal("Invalid payload UNREGISTER!")); -+ this.disconnect(Component.literal("Invalid payload UNREGISTER!"), PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause - } - } else { - try { -@@ -204,7 +204,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), identifier.toString(), data); - } catch (Exception ex) { - ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t dispatch custom payload", ex); -- this.disconnect(Component.literal("Invalid custom payload!")); -+ this.disconnect(Component.literal("Invalid custom payload!"), PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause - } - } - -@@ -220,7 +220,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - PacketUtils.ensureRunningOnSameThread(packet, this, (BlockableEventLoop) this.server); - if (packet.action() == ServerboundResourcePackPacket.Action.DECLINED && this.server.isResourcePackRequired()) { - ServerCommonPacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack {} rejection", this.playerProfile().getName(), packet.id()); -- this.disconnect((Component) Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); -+ this.disconnect((Component) Component.translatable("multiplayer.requiredTexturePrompt.disconnect"), PlayerKickEvent.Cause.RESOURCE_PACK_REJECTION); // Paper - kick event cause - } - // Paper start - adventure pack callbacks - // call the callbacks before the previously-existing event so the event has final say -@@ -250,7 +250,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - return; - } - // CraftBukkit end -- this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY); -+ this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY, PlayerKickEvent.Cause.INVALID_COOKIE); // Paper - kick event cause - } - - protected void keepConnectionAlive() { -@@ -262,7 +262,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - - if (!this.isSingleplayerOwner() && elapsedTime >= 15000L) { // Paper - use vanilla's 15000L between keep alive packets - if (this.keepAlivePending && !this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // Paper - check keepalive limit, don't fire if already disconnected -- this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE); -+ this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause - } else if (this.checkIfClosed(currentTime)) { // Paper - this.keepAlivePending = true; - this.keepAliveTime = currentTime; -@@ -278,7 +278,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - private boolean checkIfClosed(long time) { - if (this.closed) { - if (time - this.closedListenerTime >= 15000L) { -- this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE); -+ this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause - } - - return false; -@@ -330,15 +330,25 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - - // Paper start - adventure - public void disconnect(final net.kyori.adventure.text.Component reason) { -- this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(reason)); -+ this.disconnect(reason, PlayerKickEvent.Cause.UNKNOWN); -+ } -+ public void disconnect(final net.kyori.adventure.text.Component reason, PlayerKickEvent.Cause cause) { -+ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(reason), cause); -+ // Paper end - kick event causes - } - // Paper end - adventure - -+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - kick event causes - public void disconnect(Component reason) { -- this.disconnect(new DisconnectionDetails(reason)); -+ // Paper start - kick event causes -+ this.disconnect(reason, PlayerKickEvent.Cause.UNKNOWN); -+ } -+ public void disconnect(final Component reason, PlayerKickEvent.Cause cause) { -+ this.disconnect(new DisconnectionDetails(reason), cause); -+ // Paper end - kick event causes - } - -- public void disconnect(DisconnectionDetails disconnectionInfo) { -+ public void disconnect(DisconnectionDetails disconnectionInfo, PlayerKickEvent.Cause cause) { // Paper - kick event cause - // CraftBukkit start - fire PlayerKickEvent - if (this.processedDisconnect) { - return; -@@ -347,7 +357,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - Waitable waitable = new Waitable() { - @Override - protected Object evaluate() { -- ServerCommonPacketListenerImpl.this.disconnect(disconnectionInfo); -+ ServerCommonPacketListenerImpl.this.disconnect(disconnectionInfo, cause); // Paper - kick event causes - return null; - } - }; -@@ -366,7 +376,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - - net.kyori.adventure.text.Component leaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? this.player.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(this.player.getScoreboardName())); // Paper - Adventure - -- PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(disconnectionInfo.reason()), leaveMessage); // Paper - adventure -+ PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(disconnectionInfo.reason()), leaveMessage, cause); // Paper - adventure & kick event causes - - if (this.cserver.getServer().isRunning()) { - this.cserver.getPluginManager().callEvent(event); -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 5e809ac566834307ced0c56727c42fc712f026df..8f1188bd5e9e1ae7e5318674038c2d7f87d743b7 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -361,7 +361,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger() && !this.player.isDeadOrDying()) { - if (++this.aboveGroundTickCount > this.getMaximumFlyingTicks(this.player)) { - ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating too long!", this.player.getName().getString()); -- this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer); // Paper - use configurable kick message -+ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_PLAYER); // Paper - use configurable kick message & kick event cause - return; - } - } else { -@@ -380,7 +380,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - if (this.clientVehicleIsFloating && this.lastVehicle.getControllingPassenger() == this.player) { - if (++this.aboveGroundVehicleTickCount > this.getMaximumFlyingTicks(this.lastVehicle)) { - ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating a vehicle too long!", this.player.getName().getString()); -- this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle); // Paper - use configurable kick message -+ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_VEHICLE); // Paper - use configurable kick message & kick event cause - return; - } - } else { -@@ -400,7 +400,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.dropSpamThrottler.tick(); - if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { - this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 -- this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling")); -+ this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause - } - - } -@@ -488,7 +488,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - public void handleMoveVehicle(ServerboundMoveVehiclePacket packet) { - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); - if (ServerGamePacketListenerImpl.containsInvalidValues(packet.position().x(), packet.position().y(), packet.position().z(), packet.yRot(), packet.xRot())) { -- this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_vehicle_movement")); -+ 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() && this.player.hasClientLoaded()) { - Entity entity = this.player.getRootVehicle(); - -@@ -687,7 +687,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); - if (packet.getId() == this.awaitingTeleport) { - if (this.awaitingPositionFromClient == null) { -- this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement")); -+ this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause - return; - } - -@@ -754,7 +754,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper - AsyncTabCompleteEvent; run this async - // CraftBukkit start - if (!this.tabSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { // Paper - configurable tab spam limits -- this.disconnect(Component.translatable("disconnect.spam")); -+ this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause - return; - } - // CraftBukkit end -@@ -1178,14 +1178,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - if (byteTotal > byteAllowed) { - ServerGamePacketListenerImpl.LOGGER.warn("{} tried to send a book too large. Book size: {} - Allowed: {} - Pages: {}", this.player.getScoreboardName(), byteTotal, byteAllowed, pageList.size()); -- this.disconnect(Component.literal("Book too large!")); -+ this.disconnect(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause - return; - } - } - // Paper end - Book size limits - // CraftBukkit start - if (this.lastBookTick + 20 > MinecraftServer.currentTick) { -- this.disconnect(Component.literal("Book edited too quickly!")); -+ this.disconnect(Component.literal("Book edited too quickly!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause - return; - } - this.lastBookTick = MinecraftServer.currentTick; -@@ -1294,7 +1294,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - public void handleMovePlayer(ServerboundMovePlayerPacket packet) { - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); - if (ServerGamePacketListenerImpl.containsInvalidValues(packet.getX(0.0D), packet.getY(0.0D), packet.getZ(0.0D), packet.getYRot(0.0F), packet.getXRot(0.0F))) { -- this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement")); -+ this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause - } else { - ServerLevel worldserver = this.player.serverLevel(); - -@@ -1734,7 +1734,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.dropCount++; - if (this.dropCount >= 20) { - ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " dropped their items too quickly!"); -- this.disconnect(Component.literal("You dropped your items too quickly (Hacking?)")); -+ this.disconnect(Component.literal("You dropped your items too quickly (Hacking?)"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause - return; - } - } -@@ -2036,7 +2036,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.player.resetLastActionTime(); - } else { - ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString()); -- this.disconnect(Component.literal("Invalid hotbar selection (Hacking?)")); // CraftBukkit -+ this.disconnect(Component.literal("Invalid hotbar selection (Hacking?)"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // CraftBukkit // Paper - kick event cause - } - } - -@@ -2234,7 +2234,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - private void tryHandleChat(String s, Runnable runnable, boolean sync) { // CraftBukkit - if (ServerGamePacketListenerImpl.isChatMessageIllegal(s)) { -- this.disconnect((Component) Component.translatable("multiplayer.disconnect.illegal_characters")); -+ this.disconnect((Component) Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - } else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales - this.send(new ClientboundSystemChatPacket(Component.translatable("chat.disabled.options").withStyle(ChatFormatting.RED), false)); - } else { -@@ -2257,7 +2257,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - if (optional.isEmpty()) { - ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); -- this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED); -+ this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes - } - - return optional; -@@ -2438,7 +2438,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - // this.chatSpamThrottler.increment(); - if (!this.chatSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { - // CraftBukkit end -- this.disconnect((Component) Component.translatable("disconnect.spam")); -+ this.disconnect((Component) Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause - } - - } -@@ -2450,7 +2450,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - synchronized (this.lastSeenMessages) { - if (!this.lastSeenMessages.applyOffset(packet.offset())) { - ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); -- this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED); -+ this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes - } - - } -@@ -2603,7 +2603,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - - if (i > 4096) { -- this.disconnect((Component) Component.translatable("multiplayer.disconnect.too_many_pending_chats")); -+ this.disconnect((Component) Component.translatable("multiplayer.disconnect.too_many_pending_chats"), org.bukkit.event.player.PlayerKickEvent.Cause.TOO_MANY_PENDING_CHATS); // Paper - kick event cause - } - - } -@@ -2662,7 +2662,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - // Spigot Start - if ( entity == this.player && !this.player.isSpectator() ) - { -- this.disconnect( Component.literal( "Cannot interact with self!" ) ); -+ this.disconnect( Component.literal( "Cannot interact with self!" ), org.bukkit.event.player.PlayerKickEvent.Cause.SELF_INTERACTION ); // Paper - kick event cause - return; - } - // Spigot End -@@ -2778,7 +2778,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - } - -- ServerGamePacketListenerImpl.this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_entity_attacked")); -+ ServerGamePacketListenerImpl.this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_entity_attacked"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_ENTITY_ATTACKED); // Paper - add cause - ServerGamePacketListenerImpl.LOGGER.warn("Player {} tried to attack an invalid entity", ServerGamePacketListenerImpl.this.player.getName().getString()); - } - }); -@@ -3178,7 +3178,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - // Paper start - auto recipe limit - if (!org.bukkit.Bukkit.isPrimaryThread()) { - if (!this.recipeSpamPackets.isIncrementAndUnderThreshold()) { -- this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam")); -+ this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause - return; - } - } -@@ -3440,7 +3440,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - if (!Objects.equals(profilepublickey_a, profilepublickey_a1)) { - if (profilepublickey_a != null && profilepublickey_a1.expiresAt().isBefore(profilepublickey_a.expiresAt())) { -- this.disconnect(ProfilePublicKey.EXPIRED_PROFILE_PUBLIC_KEY); -+ this.disconnect(ProfilePublicKey.EXPIRED_PROFILE_PUBLIC_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes - } else { - try { - SignatureValidator signaturevalidator = this.server.getProfileKeySignatureValidator(); -@@ -3453,7 +3453,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()); -- this.disconnect(profilepublickey_b.getComponent()); -+ this.disconnect(profilepublickey_b.getComponent(), profilepublickey_b.kickCause); // Paper - kick event causes - } - - } -diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 9d5723cdfdbf6257a71e57842aea9ba317fc049a..1e4b288f20153ce0c91fabf164c5c8320c90ba7d 100644 ---- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -70,7 +70,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - } - - @Override -- public void kickPlayer(Component reason) { -+ public void kickPlayer(Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { // Paper - kick event causes - during login, no event can be called. - this.disconnect(reason); - } - // 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 ee6a3e8a8827468d787f5aa116d9876ae7654352..0dbbf067bab9f2ceb5994a1d9a411e2c1824ad16 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -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 -- entityplayer.connection.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login")); -+ entityplayer.connection.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login"), org.bukkit.event.player.PlayerKickEvent.Cause.DUPLICATE_LOGIN); // Paper - kick event cause - } - - // Instead of kicking then returning, we need to store the kick reason -@@ -1237,7 +1237,7 @@ public abstract class PlayerList { - // Paper end - // CraftBukkit start - disconnect safely - for (ServerPlayer player : this.players) { -- if (isRestarting) player.connection.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.restartMessage)); else // Paper -+ if (isRestarting) player.connection.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.restartMessage), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); else // Paper - kick event cause (cause is never used here) - player.connection.disconnect(java.util.Objects.requireNonNullElseGet(this.server.server.shutdownMessage(), net.kyori.adventure.text.Component::empty)); // CraftBukkit - add custom shutdown message // Paper - Adventure - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java b/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java -index 9e2ad78b12cadbf0e2bda1e12fe844120529c347..6a7d7fad990fc44fdda6849d43dad141e61f7f37 100644 ---- a/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java -+++ b/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java -@@ -24,7 +24,7 @@ public record ProfilePublicKey(ProfilePublicKey.Data data) { - - public static ProfilePublicKey createValidated(SignatureValidator servicesSignatureVerifier, UUID playerUuid, ProfilePublicKey.Data publicKeyData) throws ProfilePublicKey.ValidationException { - if (!publicKeyData.validateSignature(servicesSignatureVerifier, playerUuid)) { -- throw new ProfilePublicKey.ValidationException(INVALID_SIGNATURE); -+ throw new ProfilePublicKey.ValidationException(INVALID_SIGNATURE, org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PUBLIC_KEY_SIGNATURE); // Paper - kick event causes - } else { - return new ProfilePublicKey(publicKeyData); - } -@@ -88,8 +88,16 @@ public record ProfilePublicKey(ProfilePublicKey.Data data) { - } - - public static class ValidationException extends ThrowingComponent { -+ public final org.bukkit.event.player.PlayerKickEvent.Cause kickCause; // Paper -+ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - public ValidationException(Component messageText) { -+ // Paper start -+ this(messageText, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); -+ } -+ public ValidationException(Component messageText, org.bukkit.event.player.PlayerKickEvent.Cause kickCause) { -+ // Paper end - super(messageText); -+ this.kickCause = kickCause; // Paper - } - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 0b151a66d7419653088526bd72119ebd2d6dd18e..ff8d6a0ceb41258541c0049464dc0923ed4872bd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -280,7 +280,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - void sendPacket(Packet packet); - -- void kickPlayer(Component reason); -+ void kickPlayer(Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause); // Paper - kick event causes - } - - public record CookieFuture(ResourceLocation key, CompletableFuture future) { -@@ -640,7 +640,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - @Override - public void kickPlayer(String message) { - org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot -- this.getHandle().transferCookieConnection.kickPlayer(CraftChatMessage.fromStringOrEmpty(message, true)); -+ this.getHandle().transferCookieConnection.kickPlayer(CraftChatMessage.fromStringOrEmpty(message, true), org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); // Paper - kick event cause - } - - // Paper start -@@ -652,10 +652,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public void kick(final net.kyori.adventure.text.Component message) { -+ kick(message, org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); -+ } -+ -+ @Override -+ public void kick(net.kyori.adventure.text.Component message, org.bukkit.event.player.PlayerKickEvent.Cause cause) { - org.spigotmc.AsyncCatcher.catchOp("player kick"); - final ServerGamePacketListenerImpl connection = this.getHandle().connection; - if (connection != null) { -- connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message); -+ connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message, cause); - } - } - -@@ -716,7 +721,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - // Paper start - Improve chat handling - if (ServerGamePacketListenerImpl.isChatMessageIllegal(msg)) { -- this.getHandle().connection.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters")); -+ this.getHandle().connection.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - kick event causes - } else { - if (msg.startsWith("/")) { - this.getHandle().connection.handleCommand(msg); -diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java -index 824c4ad135ea5177f416687c7042639ed126b70b..39e56b95aaafbcd8ebe68fdefaace83702e9510d 100644 ---- a/src/main/java/org/spigotmc/RestartCommand.java -+++ b/src/main/java/org/spigotmc/RestartCommand.java -@@ -74,7 +74,7 @@ public class RestartCommand extends Command - // Kick all players - for ( ServerPlayer p : com.google.common.collect.ImmutableList.copyOf( MinecraftServer.getServer().getPlayerList().players ) ) - { -- p.connection.disconnect( CraftChatMessage.fromStringOrEmpty( SpigotConfig.restartMessage, true ) ); -+ p.connection.disconnect( CraftChatMessage.fromStringOrEmpty( SpigotConfig.restartMessage, true ), org.bukkit.event.player.PlayerKickEvent.Cause.RESTART_COMMAND); // Paper - kick event reason (cause is never used)) - } - // Give the socket a chance to send the packets - try diff --git a/patches/server/0536-Add-PufferFishStateChangeEvent.patch b/patches/server/0536-Add-PufferFishStateChangeEvent.patch new file mode 100644 index 0000000000..0574c7ed8c --- /dev/null +++ b/patches/server/0536-Add-PufferFishStateChangeEvent.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: HexedHero <6012891+HexedHero@users.noreply.github.com> +Date: Mon, 10 May 2021 16:59:05 +0100 +Subject: [PATCH] Add PufferFishStateChangeEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java +index 6c5fa151867eb2b15b9aaf94eb4f5309c415a92b..cdb74f86ee92ee143af29962a85d45ca585cee44 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java +@@ -102,25 +102,39 @@ public class Pufferfish extends AbstractFish { + public void tick() { + if (!this.level().isClientSide && this.isAlive() && this.isEffectiveAi()) { + if (this.inflateCounter > 0) { ++ boolean increase = true; // Paper - Add PufferFishStateChangeEvent + if (this.getPuffState() == 0) { ++ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 1).callEvent()) { // Paper - Add PufferFishStateChangeEvent + this.makeSound(SoundEvents.PUFFER_FISH_BLOW_UP); + this.setPuffState(1); ++ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent + } else if (this.inflateCounter > 40 && this.getPuffState() == 1) { ++ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 2).callEvent()) { // Paper - Add PufferFishStateChangeEvent + this.makeSound(SoundEvents.PUFFER_FISH_BLOW_UP); + this.setPuffState(2); ++ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent + } + ++ if (increase) { // Paper - Add PufferFishStateChangeEvent + ++this.inflateCounter; ++ } // Paper - Add PufferFishStateChangeEvent + } else if (this.getPuffState() != 0) { ++ boolean increase = true; // Paper - Add PufferFishStateChangeEvent + if (this.deflateTimer > 60 && this.getPuffState() == 2) { ++ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 1).callEvent()) { // Paper - Add PufferFishStateChangeEvent + this.makeSound(SoundEvents.PUFFER_FISH_BLOW_OUT); + this.setPuffState(1); ++ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent + } else if (this.deflateTimer > 100 && this.getPuffState() == 1) { ++ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 0).callEvent()) { // Paper - Add PufferFishStateChangeEvent + this.makeSound(SoundEvents.PUFFER_FISH_BLOW_OUT); + this.setPuffState(0); ++ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent + } + ++ if (increase) { // Paper - Add PufferFishStateChangeEvent + ++this.deflateTimer; ++ } // Paper - Add PufferFishStateChangeEvent + } + } + diff --git a/patches/server/0537-Add-PufferFishStateChangeEvent.patch b/patches/server/0537-Add-PufferFishStateChangeEvent.patch deleted file mode 100644 index 0574c7ed8c..0000000000 --- a/patches/server/0537-Add-PufferFishStateChangeEvent.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: HexedHero <6012891+HexedHero@users.noreply.github.com> -Date: Mon, 10 May 2021 16:59:05 +0100 -Subject: [PATCH] Add PufferFishStateChangeEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java -index 6c5fa151867eb2b15b9aaf94eb4f5309c415a92b..cdb74f86ee92ee143af29962a85d45ca585cee44 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java -@@ -102,25 +102,39 @@ public class Pufferfish extends AbstractFish { - public void tick() { - if (!this.level().isClientSide && this.isAlive() && this.isEffectiveAi()) { - if (this.inflateCounter > 0) { -+ boolean increase = true; // Paper - Add PufferFishStateChangeEvent - if (this.getPuffState() == 0) { -+ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 1).callEvent()) { // Paper - Add PufferFishStateChangeEvent - this.makeSound(SoundEvents.PUFFER_FISH_BLOW_UP); - this.setPuffState(1); -+ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent - } else if (this.inflateCounter > 40 && this.getPuffState() == 1) { -+ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 2).callEvent()) { // Paper - Add PufferFishStateChangeEvent - this.makeSound(SoundEvents.PUFFER_FISH_BLOW_UP); - this.setPuffState(2); -+ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent - } - -+ if (increase) { // Paper - Add PufferFishStateChangeEvent - ++this.inflateCounter; -+ } // Paper - Add PufferFishStateChangeEvent - } else if (this.getPuffState() != 0) { -+ boolean increase = true; // Paper - Add PufferFishStateChangeEvent - if (this.deflateTimer > 60 && this.getPuffState() == 2) { -+ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 1).callEvent()) { // Paper - Add PufferFishStateChangeEvent - this.makeSound(SoundEvents.PUFFER_FISH_BLOW_OUT); - this.setPuffState(1); -+ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent - } else if (this.deflateTimer > 100 && this.getPuffState() == 1) { -+ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 0).callEvent()) { // Paper - Add PufferFishStateChangeEvent - this.makeSound(SoundEvents.PUFFER_FISH_BLOW_OUT); - this.setPuffState(0); -+ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent - } - -+ if (increase) { // Paper - Add PufferFishStateChangeEvent - ++this.deflateTimer; -+ } // Paper - Add PufferFishStateChangeEvent - } - } - diff --git a/patches/server/0537-Fix-PlayerBucketEmptyEvent-result-itemstack.patch b/patches/server/0537-Fix-PlayerBucketEmptyEvent-result-itemstack.patch new file mode 100644 index 0000000000..646e52a326 --- /dev/null +++ b/patches/server/0537-Fix-PlayerBucketEmptyEvent-result-itemstack.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 20 May 2021 22:16:37 -0700 +Subject: [PATCH] Fix PlayerBucketEmptyEvent result itemstack + +Fixes SPIGOT-2560: https://hub.spigotmc.org/jira/projects/SPIGOT/issues/SPIGOT-2560 + +diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java +index a6aaef9de23bf8084ab13c8f704e9f59de3acdcf..002e2f8e956b2631529e2189be225385dfb501df 100644 +--- a/src/main/java/net/minecraft/world/item/BucketItem.java ++++ b/src/main/java/net/minecraft/world/item/BucketItem.java +@@ -40,6 +40,8 @@ import org.bukkit.event.player.PlayerBucketFillEvent; + + public class BucketItem extends Item implements DispensibleContainerItem { + ++ private static @Nullable ItemStack itemLeftInHandAfterPlayerBucketEmptyEvent = null; // Paper - Fix PlayerBucketEmptyEvent result itemstack ++ + public final Fluid content; + + public BucketItem(Fluid fluid, Item.Properties settings) { +@@ -125,6 +127,13 @@ public class BucketItem extends Item implements DispensibleContainerItem { + } + + public static ItemStack getEmptySuccessItem(ItemStack stack, Player player) { ++ // Paper start - Fix PlayerBucketEmptyEvent result itemstack ++ if (itemLeftInHandAfterPlayerBucketEmptyEvent != null) { ++ ItemStack itemInHand = itemLeftInHandAfterPlayerBucketEmptyEvent; ++ itemLeftInHandAfterPlayerBucketEmptyEvent = null; ++ return itemInHand; ++ } ++ // Paper end - Fix PlayerBucketEmptyEvent result itemstack + return !player.hasInfiniteMaterials() ? new ItemStack(Items.BUCKET) : stack; + } + +@@ -182,6 +191,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { + ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541 + return false; + } ++ itemLeftInHandAfterPlayerBucketEmptyEvent = event.getItemStack() != null ? event.getItemStack().equals(CraftItemStack.asNewCraftStack(net.minecraft.world.item.Items.BUCKET)) ? null : CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; // Paper - Fix PlayerBucketEmptyEvent result itemstack + } + // CraftBukkit end + if (!flag2) { diff --git a/patches/server/0538-Fix-PlayerBucketEmptyEvent-result-itemstack.patch b/patches/server/0538-Fix-PlayerBucketEmptyEvent-result-itemstack.patch deleted file mode 100644 index 646e52a326..0000000000 --- a/patches/server/0538-Fix-PlayerBucketEmptyEvent-result-itemstack.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 20 May 2021 22:16:37 -0700 -Subject: [PATCH] Fix PlayerBucketEmptyEvent result itemstack - -Fixes SPIGOT-2560: https://hub.spigotmc.org/jira/projects/SPIGOT/issues/SPIGOT-2560 - -diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java -index a6aaef9de23bf8084ab13c8f704e9f59de3acdcf..002e2f8e956b2631529e2189be225385dfb501df 100644 ---- a/src/main/java/net/minecraft/world/item/BucketItem.java -+++ b/src/main/java/net/minecraft/world/item/BucketItem.java -@@ -40,6 +40,8 @@ import org.bukkit.event.player.PlayerBucketFillEvent; - - public class BucketItem extends Item implements DispensibleContainerItem { - -+ private static @Nullable ItemStack itemLeftInHandAfterPlayerBucketEmptyEvent = null; // Paper - Fix PlayerBucketEmptyEvent result itemstack -+ - public final Fluid content; - - public BucketItem(Fluid fluid, Item.Properties settings) { -@@ -125,6 +127,13 @@ public class BucketItem extends Item implements DispensibleContainerItem { - } - - public static ItemStack getEmptySuccessItem(ItemStack stack, Player player) { -+ // Paper start - Fix PlayerBucketEmptyEvent result itemstack -+ if (itemLeftInHandAfterPlayerBucketEmptyEvent != null) { -+ ItemStack itemInHand = itemLeftInHandAfterPlayerBucketEmptyEvent; -+ itemLeftInHandAfterPlayerBucketEmptyEvent = null; -+ return itemInHand; -+ } -+ // Paper end - Fix PlayerBucketEmptyEvent result itemstack - return !player.hasInfiniteMaterials() ? new ItemStack(Items.BUCKET) : stack; - } - -@@ -182,6 +191,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { - ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541 - return false; - } -+ itemLeftInHandAfterPlayerBucketEmptyEvent = event.getItemStack() != null ? event.getItemStack().equals(CraftItemStack.asNewCraftStack(net.minecraft.world.item.Items.BUCKET)) ? null : CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; // Paper - Fix PlayerBucketEmptyEvent result itemstack - } - // CraftBukkit end - if (!flag2) { diff --git a/patches/server/0538-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch b/patches/server/0538-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch new file mode 100644 index 0000000000..ee4d412a1c --- /dev/null +++ b/patches/server/0538-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 29 May 2020 20:29:02 -0400 +Subject: [PATCH] Synchronize PalettedContainer instead of + ThreadingDetector/Semaphore + +Mojang has flaws in their logic about chunks being concurrently +wrote to. So we constantly see crashes around multiple threads writing. + +Additionally, java has optimized synchronization so well that its +in many times faster than trying to manage read write locks for low +contention situations. + +And this is extremely a low contention situation. + +diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java +index 8c318c5f9eaaae1e961ff24247283c232fa84c20..112d1259dd37743076ff6c67ffd711d084ba8698 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java ++++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java +@@ -30,14 +30,14 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + public final IdMap registry; + private volatile PalettedContainer.Data data; + private final PalettedContainer.Strategy strategy; +- private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); ++ // private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused + + public void acquire() { +- this.threadingDetector.checkAndLock(); ++ // this.threadingDetector.checkAndLock(); // Paper - disable this - use proper synchronization + } + + public void release() { +- this.threadingDetector.checkAndUnlock(); ++ // this.threadingDetector.checkAndUnlock(); // Paper - disable this + } + + public static Codec> codecRW(IdMap idList, Codec entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) { +@@ -110,7 +110,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + } + + @Override +- public int onResize(int newBits, T object) { ++ public synchronized int onResize(int newBits, T object) { // Paper - synchronize + PalettedContainer.Data data = this.data; + PalettedContainer.Data data2 = this.createOrReuseData(data, newBits); + data2.copyFrom(data.palette, data.storage); +@@ -135,7 +135,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + return this.getAndSet(this.strategy.getIndex(x, y, z), value); + } + +- private T getAndSet(int index, T value) { ++ private synchronized T getAndSet(int index, T value) { // Paper - synchronize + int i = this.data.palette.idFor(value); + int j = this.data.storage.getAndSet(index, i); + return this.data.palette.valueFor(j); +@@ -151,7 +151,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + } + } + +- private void set(int index, T value) { ++ private synchronized void set(int index, T value) { // Paper - synchronize + int i = this.data.palette.idFor(value); + this.data.storage.set(index, i); + } +@@ -174,7 +174,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + intSet.forEach(id -> action.accept(palette.valueFor(id))); + } + +- public void read(FriendlyByteBuf buf) { ++ public synchronized void read(FriendlyByteBuf buf) { // Paper - synchronize + this.acquire(); + + try { +@@ -189,7 +189,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + } + + @Override +- public void write(FriendlyByteBuf buf) { ++ public synchronized void write(FriendlyByteBuf buf) { // Paper - synchronize + this.acquire(); + + try { +@@ -237,7 +237,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + } + + @Override +- public PalettedContainerRO.PackedData pack(IdMap idList, PalettedContainer.Strategy paletteProvider) { ++ public synchronized PalettedContainerRO.PackedData pack(IdMap idList, PalettedContainer.Strategy paletteProvider) { // Paper - synchronize + this.acquire(); + + PalettedContainerRO.PackedData var12; diff --git a/patches/server/0539-Add-option-to-fix-items-merging-through-walls.patch b/patches/server/0539-Add-option-to-fix-items-merging-through-walls.patch new file mode 100644 index 0000000000..b4e4e39ae1 --- /dev/null +++ b/patches/server/0539-Add-option-to-fix-items-merging-through-walls.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: GioSDA +Date: Wed, 10 Mar 2021 10:06:45 -0800 +Subject: [PATCH] Add option to fix items merging through walls + + +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 9974aec00935a1c3068eceee6d7042f14f15ac56..586257fe5c9f5cddd0ed164254f46777c6e71d66 100644 +--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java ++++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +@@ -285,6 +285,14 @@ public class ItemEntity extends Entity implements TraceableEntity { + ItemEntity entityitem = (ItemEntity) iterator.next(); + + if (entityitem.isMergable()) { ++ // Paper start - Fix items merging through walls ++ if (this.level().paperConfig().fixes.fixItemsMergingThroughWalls) { ++ if (this.level().clipDirect(this.position(), entityitem.position(), ++ net.minecraft.world.phys.shapes.CollisionContext.of(this)) == net.minecraft.world.phys.HitResult.Type.BLOCK) { ++ continue; ++ } ++ } ++ // Paper end - Fix items merging through walls + this.tryToMerge(entityitem); + if (this.isRemoved()) { + break; diff --git a/patches/server/0539-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch b/patches/server/0539-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch deleted file mode 100644 index ee4d412a1c..0000000000 --- a/patches/server/0539-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 29 May 2020 20:29:02 -0400 -Subject: [PATCH] Synchronize PalettedContainer instead of - ThreadingDetector/Semaphore - -Mojang has flaws in their logic about chunks being concurrently -wrote to. So we constantly see crashes around multiple threads writing. - -Additionally, java has optimized synchronization so well that its -in many times faster than trying to manage read write locks for low -contention situations. - -And this is extremely a low contention situation. - -diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -index 8c318c5f9eaaae1e961ff24247283c232fa84c20..112d1259dd37743076ff6c67ffd711d084ba8698 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -@@ -30,14 +30,14 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - public final IdMap registry; - private volatile PalettedContainer.Data data; - private final PalettedContainer.Strategy strategy; -- private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); -+ // private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused - - public void acquire() { -- this.threadingDetector.checkAndLock(); -+ // this.threadingDetector.checkAndLock(); // Paper - disable this - use proper synchronization - } - - public void release() { -- this.threadingDetector.checkAndUnlock(); -+ // this.threadingDetector.checkAndUnlock(); // Paper - disable this - } - - public static Codec> codecRW(IdMap idList, Codec entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) { -@@ -110,7 +110,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - } - - @Override -- public int onResize(int newBits, T object) { -+ public synchronized int onResize(int newBits, T object) { // Paper - synchronize - PalettedContainer.Data data = this.data; - PalettedContainer.Data data2 = this.createOrReuseData(data, newBits); - data2.copyFrom(data.palette, data.storage); -@@ -135,7 +135,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - return this.getAndSet(this.strategy.getIndex(x, y, z), value); - } - -- private T getAndSet(int index, T value) { -+ private synchronized T getAndSet(int index, T value) { // Paper - synchronize - int i = this.data.palette.idFor(value); - int j = this.data.storage.getAndSet(index, i); - return this.data.palette.valueFor(j); -@@ -151,7 +151,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - } - } - -- private void set(int index, T value) { -+ private synchronized void set(int index, T value) { // Paper - synchronize - int i = this.data.palette.idFor(value); - this.data.storage.set(index, i); - } -@@ -174,7 +174,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - intSet.forEach(id -> action.accept(palette.valueFor(id))); - } - -- public void read(FriendlyByteBuf buf) { -+ public synchronized void read(FriendlyByteBuf buf) { // Paper - synchronize - this.acquire(); - - try { -@@ -189,7 +189,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - } - - @Override -- public void write(FriendlyByteBuf buf) { -+ public synchronized void write(FriendlyByteBuf buf) { // Paper - synchronize - this.acquire(); - - try { -@@ -237,7 +237,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - } - - @Override -- public PalettedContainerRO.PackedData pack(IdMap idList, PalettedContainer.Strategy paletteProvider) { -+ public synchronized PalettedContainerRO.PackedData pack(IdMap idList, PalettedContainer.Strategy paletteProvider) { // Paper - synchronize - this.acquire(); - - PalettedContainerRO.PackedData var12; diff --git a/patches/server/0540-Add-BellRevealRaiderEvent.patch b/patches/server/0540-Add-BellRevealRaiderEvent.patch new file mode 100644 index 0000000000..871aa2a198 --- /dev/null +++ b/patches/server/0540-Add-BellRevealRaiderEvent.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 26 May 2021 17:09:07 -0400 +Subject: [PATCH] Add BellRevealRaiderEvent + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java +index 86dac3f82da065bf79d94da9df192f51ce4665e2..946c9dbfabf154db53d811906fd98d17992167d1 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java +@@ -156,7 +156,7 @@ public class BellBlockEntity extends BlockEntity { + return BellBlockEntity.isRaiderWithinRange(pos, entityliving); + }).map((entity) -> (org.bukkit.entity.LivingEntity) entity.getBukkitEntity()).collect(java.util.stream.Collectors.toCollection(java.util.ArrayList::new)); // CraftBukkit + +- org.bukkit.craftbukkit.event.CraftEventFactory.handleBellResonateEvent(world, pos, entities).forEach(BellBlockEntity::glow); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBellResonateEvent(world, pos, entities).forEach(entity -> glow(entity, pos)); // Paper - Add BellRevealRaiderEvent + // CraftBukkit end + } + +@@ -189,6 +189,13 @@ public class BellBlockEntity extends BlockEntity { + } + + private static void glow(LivingEntity entity) { ++ // Paper start - Add BellRevealRaiderEvent ++ glow(entity, null); ++ } ++ ++ private static void glow(LivingEntity entity, @javax.annotation.Nullable BlockPos pos) { ++ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(org.bukkit.craftbukkit.block.CraftBlock.at(entity.level(), pos), (org.bukkit.entity.Raider) entity.getBukkitEntity()).callEvent()) return; ++ // Paper end - Add BellRevealRaiderEvent + entity.addEffect(new MobEffectInstance(MobEffects.GLOWING, 60)); + } + diff --git a/patches/server/0540-Add-option-to-fix-items-merging-through-walls.patch b/patches/server/0540-Add-option-to-fix-items-merging-through-walls.patch deleted file mode 100644 index b4e4e39ae1..0000000000 --- a/patches/server/0540-Add-option-to-fix-items-merging-through-walls.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: GioSDA -Date: Wed, 10 Mar 2021 10:06:45 -0800 -Subject: [PATCH] Add option to fix items merging through walls - - -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 9974aec00935a1c3068eceee6d7042f14f15ac56..586257fe5c9f5cddd0ed164254f46777c6e71d66 100644 ---- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -@@ -285,6 +285,14 @@ public class ItemEntity extends Entity implements TraceableEntity { - ItemEntity entityitem = (ItemEntity) iterator.next(); - - if (entityitem.isMergable()) { -+ // Paper start - Fix items merging through walls -+ if (this.level().paperConfig().fixes.fixItemsMergingThroughWalls) { -+ if (this.level().clipDirect(this.position(), entityitem.position(), -+ net.minecraft.world.phys.shapes.CollisionContext.of(this)) == net.minecraft.world.phys.HitResult.Type.BLOCK) { -+ continue; -+ } -+ } -+ // Paper end - Fix items merging through walls - this.tryToMerge(entityitem); - if (this.isRemoved()) { - break; diff --git a/patches/server/0541-Add-BellRevealRaiderEvent.patch b/patches/server/0541-Add-BellRevealRaiderEvent.patch deleted file mode 100644 index 871aa2a198..0000000000 --- a/patches/server/0541-Add-BellRevealRaiderEvent.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Wed, 26 May 2021 17:09:07 -0400 -Subject: [PATCH] Add BellRevealRaiderEvent - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java -index 86dac3f82da065bf79d94da9df192f51ce4665e2..946c9dbfabf154db53d811906fd98d17992167d1 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java -@@ -156,7 +156,7 @@ public class BellBlockEntity extends BlockEntity { - return BellBlockEntity.isRaiderWithinRange(pos, entityliving); - }).map((entity) -> (org.bukkit.entity.LivingEntity) entity.getBukkitEntity()).collect(java.util.stream.Collectors.toCollection(java.util.ArrayList::new)); // CraftBukkit - -- org.bukkit.craftbukkit.event.CraftEventFactory.handleBellResonateEvent(world, pos, entities).forEach(BellBlockEntity::glow); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBellResonateEvent(world, pos, entities).forEach(entity -> glow(entity, pos)); // Paper - Add BellRevealRaiderEvent - // CraftBukkit end - } - -@@ -189,6 +189,13 @@ public class BellBlockEntity extends BlockEntity { - } - - private static void glow(LivingEntity entity) { -+ // Paper start - Add BellRevealRaiderEvent -+ glow(entity, null); -+ } -+ -+ private static void glow(LivingEntity entity, @javax.annotation.Nullable BlockPos pos) { -+ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(org.bukkit.craftbukkit.block.CraftBlock.at(entity.level(), pos), (org.bukkit.entity.Raider) entity.getBukkitEntity()).callEvent()) return; -+ // Paper end - Add BellRevealRaiderEvent - entity.addEffect(new MobEffectInstance(MobEffects.GLOWING, 60)); - } - diff --git a/patches/server/0541-Fix-invulnerable-end-crystals.patch b/patches/server/0541-Fix-invulnerable-end-crystals.patch new file mode 100644 index 0000000000..4349e5a8ad --- /dev/null +++ b/patches/server/0541-Fix-invulnerable-end-crystals.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Max Lee +Date: Thu, 27 May 2021 14:52:30 -0700 +Subject: [PATCH] Fix invulnerable end crystals + +MC-108513 + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java +index 671e8aa7ecc2b3fcc98af62356ff690a2604bcb0..7cb3d69a69e0e3ef4b7f9f9c8b1eb67edb5d116d 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java +@@ -30,6 +30,7 @@ public class EndCrystal extends Entity { + private static final EntityDataAccessor> DATA_BEAM_TARGET = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.OPTIONAL_BLOCK_POS); + private static final EntityDataAccessor DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN); + public int time; ++ public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals + + public EndCrystal(EntityType type, Level world) { + super(type, world); +@@ -68,6 +69,17 @@ public class EndCrystal extends Entity { + } + // CraftBukkit end + } ++ // Paper start - Fix invulnerable end crystals ++ if (this.level().paperConfig().unsupportedSettings.fixInvulnerableEndCrystalExploit && this.generatedByDragonFight && this.isInvulnerable()) { ++ if (!java.util.Objects.equals(((ServerLevel) this.level()).uuid, this.getOriginWorld()) ++ || ((ServerLevel) this.level()).getDragonFight() == null ++ || ((ServerLevel) this.level()).getDragonFight().respawnStage == null ++ || ((ServerLevel) this.level()).getDragonFight().respawnStage.ordinal() > net.minecraft.world.level.dimension.end.DragonRespawnAnimation.SUMMONING_DRAGON.ordinal()) { ++ this.setInvulnerable(false); ++ this.setBeamTarget(null); ++ } ++ } ++ // Paper end - Fix invulnerable end crystals + } + + } +@@ -79,6 +91,7 @@ public class EndCrystal extends Entity { + } + + nbt.putBoolean("ShowBottom", this.showsBottom()); ++ if (this.generatedByDragonFight) nbt.putBoolean("Paper.GeneratedByDragonFight", this.generatedByDragonFight); // Paper - Fix invulnerable end crystals + } + + @Override +@@ -87,6 +100,7 @@ public class EndCrystal extends Entity { + if (nbt.contains("ShowBottom", 1)) { + this.setShowBottom(nbt.getBoolean("ShowBottom")); + } ++ if (nbt.contains("Paper.GeneratedByDragonFight", 1)) this.generatedByDragonFight = nbt.getBoolean("Paper.GeneratedByDragonFight"); // Paper - Fix invulnerable end crystals + + } + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/SpikeFeature.java b/src/main/java/net/minecraft/world/level/levelgen/feature/SpikeFeature.java +index 6f0cd7121bf191d8fd01baf4c9b87df7f4f44564..fe5b2bcfaa243c3089f3df83ec1ae0948a63d1eb 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/feature/SpikeFeature.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/feature/SpikeFeature.java +@@ -115,6 +115,7 @@ public class SpikeFeature extends Feature { + endCrystal.moveTo( + (double)spike.getCenterX() + 0.5, (double)(spike.getHeight() + 1), (double)spike.getCenterZ() + 0.5, random.nextFloat() * 360.0F, 0.0F + ); ++ endCrystal.generatedByDragonFight = true; // Paper - Fix invulnerable end crystals + world.addFreshEntity(endCrystal); + BlockPos blockPos2 = endCrystal.blockPosition(); + this.setBlock(world, blockPos2.below(), Blocks.BEDROCK.defaultBlockState()); diff --git a/patches/server/0542-Add-ElderGuardianAppearanceEvent.patch b/patches/server/0542-Add-ElderGuardianAppearanceEvent.patch new file mode 100644 index 0000000000..e28248ff5d --- /dev/null +++ b/patches/server/0542-Add-ElderGuardianAppearanceEvent.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Fri, 19 Mar 2021 23:39:09 -0400 +Subject: [PATCH] Add ElderGuardianAppearanceEvent + + +diff --git a/src/main/java/net/minecraft/world/effect/MobEffectUtil.java b/src/main/java/net/minecraft/world/effect/MobEffectUtil.java +index f8026eb1d9b10e468d28ee2e1296653e873c87db..23977c2074b920b646a639bef79c0f625b284bea 100644 +--- a/src/main/java/net/minecraft/world/effect/MobEffectUtil.java ++++ b/src/main/java/net/minecraft/world/effect/MobEffectUtil.java +@@ -55,10 +55,23 @@ public final class MobEffectUtil { + } + + public static List addEffectToPlayersAround(ServerLevel worldserver, @Nullable Entity entity, Vec3 vec3d, double d0, MobEffectInstance mobeffect, int i, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { ++ // Paper start - Add ElderGuardianAppearanceEvent ++ return addEffectToPlayersAround(worldserver, entity, vec3d, d0, mobeffect, i, cause, null); ++ } ++ ++ public static List addEffectToPlayersAround(ServerLevel worldserver, @Nullable Entity entity, Vec3 vec3d, double d0, MobEffectInstance mobeffect, int i, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause, @Nullable java.util.function.Predicate playerPredicate) { ++ // Paper end - Add ElderGuardianAppearanceEvent + // CraftBukkit end + Holder holder = mobeffect.getEffect(); + List list = worldserver.getPlayers((entityplayer) -> { +- return entityplayer.gameMode.isSurvival() && (entity == null || !entity.isAlliedTo((Entity) entityplayer)) && vec3d.closerThan(entityplayer.position(), d0) && (!entityplayer.hasEffect(holder) || entityplayer.getEffect(holder).getAmplifier() < mobeffect.getAmplifier() || entityplayer.getEffect(holder).endsWithin(i - 1)); ++ // Paper start - Add ElderGuardianAppearanceEvent ++ boolean condition = entityplayer.gameMode.isSurvival() && (entity == null || !entity.isAlliedTo((Entity) entityplayer)) && vec3d.closerThan(entityplayer.position(), d0) && (!entityplayer.hasEffect(holder) || entityplayer.getEffect(holder).getAmplifier() < mobeffect.getAmplifier() || entityplayer.getEffect(holder).endsWithin(i - 1)); ++ if (condition) { ++ return playerPredicate == null || playerPredicate.test(entityplayer); // Only test the player AFTER it is true ++ } else { ++ return false; ++ } ++ // Paper ned - Add ElderGuardianAppearanceEvent + }); + + list.forEach((entityplayer) -> { +diff --git a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java +index 9290f43b4b37a7fa2afae81f8351ea76b7ee7de0..378694a38115c012978e1fea59d049d1ebd04110 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java ++++ b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java +@@ -67,7 +67,7 @@ public class ElderGuardian extends Guardian { + super.customServerAiStep(world); + if ((this.tickCount + this.getId()) % 1200 == 0) { + MobEffectInstance mobeffect = new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 6000, 2); +- List list = MobEffectUtil.addEffectToPlayersAround(world, this, this.position(), 50.0D, mobeffect, 1200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit ++ List list = MobEffectUtil.addEffectToPlayersAround(world, this, this.position(), 50.0D, mobeffect, 1200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK, (player) -> new io.papermc.paper.event.entity.ElderGuardianAppearanceEvent((org.bukkit.entity.ElderGuardian) this.getBukkitEntity(), player.getBukkitEntity()).callEvent()); // CraftBukkit // Paper - Add ElderGuardianAppearanceEvent + + list.forEach((entityplayer) -> { + entityplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, this.isSilent() ? 0.0F : 1.0F)); diff --git a/patches/server/0542-Fix-invulnerable-end-crystals.patch b/patches/server/0542-Fix-invulnerable-end-crystals.patch deleted file mode 100644 index 4349e5a8ad..0000000000 --- a/patches/server/0542-Fix-invulnerable-end-crystals.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Max Lee -Date: Thu, 27 May 2021 14:52:30 -0700 -Subject: [PATCH] Fix invulnerable end crystals - -MC-108513 - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -index 671e8aa7ecc2b3fcc98af62356ff690a2604bcb0..7cb3d69a69e0e3ef4b7f9f9c8b1eb67edb5d116d 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -@@ -30,6 +30,7 @@ public class EndCrystal extends Entity { - private static final EntityDataAccessor> DATA_BEAM_TARGET = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.OPTIONAL_BLOCK_POS); - private static final EntityDataAccessor DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN); - public int time; -+ public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals - - public EndCrystal(EntityType type, Level world) { - super(type, world); -@@ -68,6 +69,17 @@ public class EndCrystal extends Entity { - } - // CraftBukkit end - } -+ // Paper start - Fix invulnerable end crystals -+ if (this.level().paperConfig().unsupportedSettings.fixInvulnerableEndCrystalExploit && this.generatedByDragonFight && this.isInvulnerable()) { -+ if (!java.util.Objects.equals(((ServerLevel) this.level()).uuid, this.getOriginWorld()) -+ || ((ServerLevel) this.level()).getDragonFight() == null -+ || ((ServerLevel) this.level()).getDragonFight().respawnStage == null -+ || ((ServerLevel) this.level()).getDragonFight().respawnStage.ordinal() > net.minecraft.world.level.dimension.end.DragonRespawnAnimation.SUMMONING_DRAGON.ordinal()) { -+ this.setInvulnerable(false); -+ this.setBeamTarget(null); -+ } -+ } -+ // Paper end - Fix invulnerable end crystals - } - - } -@@ -79,6 +91,7 @@ public class EndCrystal extends Entity { - } - - nbt.putBoolean("ShowBottom", this.showsBottom()); -+ if (this.generatedByDragonFight) nbt.putBoolean("Paper.GeneratedByDragonFight", this.generatedByDragonFight); // Paper - Fix invulnerable end crystals - } - - @Override -@@ -87,6 +100,7 @@ public class EndCrystal extends Entity { - if (nbt.contains("ShowBottom", 1)) { - this.setShowBottom(nbt.getBoolean("ShowBottom")); - } -+ if (nbt.contains("Paper.GeneratedByDragonFight", 1)) this.generatedByDragonFight = nbt.getBoolean("Paper.GeneratedByDragonFight"); // Paper - Fix invulnerable end crystals - - } - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/SpikeFeature.java b/src/main/java/net/minecraft/world/level/levelgen/feature/SpikeFeature.java -index 6f0cd7121bf191d8fd01baf4c9b87df7f4f44564..fe5b2bcfaa243c3089f3df83ec1ae0948a63d1eb 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/feature/SpikeFeature.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/feature/SpikeFeature.java -@@ -115,6 +115,7 @@ public class SpikeFeature extends Feature { - endCrystal.moveTo( - (double)spike.getCenterX() + 0.5, (double)(spike.getHeight() + 1), (double)spike.getCenterZ() + 0.5, random.nextFloat() * 360.0F, 0.0F - ); -+ endCrystal.generatedByDragonFight = true; // Paper - Fix invulnerable end crystals - world.addFreshEntity(endCrystal); - BlockPos blockPos2 = endCrystal.blockPosition(); - this.setBlock(world, blockPos2.below(), Blocks.BEDROCK.defaultBlockState()); diff --git a/patches/server/0543-Add-ElderGuardianAppearanceEvent.patch b/patches/server/0543-Add-ElderGuardianAppearanceEvent.patch deleted file mode 100644 index e28248ff5d..0000000000 --- a/patches/server/0543-Add-ElderGuardianAppearanceEvent.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: Fri, 19 Mar 2021 23:39:09 -0400 -Subject: [PATCH] Add ElderGuardianAppearanceEvent - - -diff --git a/src/main/java/net/minecraft/world/effect/MobEffectUtil.java b/src/main/java/net/minecraft/world/effect/MobEffectUtil.java -index f8026eb1d9b10e468d28ee2e1296653e873c87db..23977c2074b920b646a639bef79c0f625b284bea 100644 ---- a/src/main/java/net/minecraft/world/effect/MobEffectUtil.java -+++ b/src/main/java/net/minecraft/world/effect/MobEffectUtil.java -@@ -55,10 +55,23 @@ public final class MobEffectUtil { - } - - public static List addEffectToPlayersAround(ServerLevel worldserver, @Nullable Entity entity, Vec3 vec3d, double d0, MobEffectInstance mobeffect, int i, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { -+ // Paper start - Add ElderGuardianAppearanceEvent -+ return addEffectToPlayersAround(worldserver, entity, vec3d, d0, mobeffect, i, cause, null); -+ } -+ -+ public static List addEffectToPlayersAround(ServerLevel worldserver, @Nullable Entity entity, Vec3 vec3d, double d0, MobEffectInstance mobeffect, int i, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause, @Nullable java.util.function.Predicate playerPredicate) { -+ // Paper end - Add ElderGuardianAppearanceEvent - // CraftBukkit end - Holder holder = mobeffect.getEffect(); - List list = worldserver.getPlayers((entityplayer) -> { -- return entityplayer.gameMode.isSurvival() && (entity == null || !entity.isAlliedTo((Entity) entityplayer)) && vec3d.closerThan(entityplayer.position(), d0) && (!entityplayer.hasEffect(holder) || entityplayer.getEffect(holder).getAmplifier() < mobeffect.getAmplifier() || entityplayer.getEffect(holder).endsWithin(i - 1)); -+ // Paper start - Add ElderGuardianAppearanceEvent -+ boolean condition = entityplayer.gameMode.isSurvival() && (entity == null || !entity.isAlliedTo((Entity) entityplayer)) && vec3d.closerThan(entityplayer.position(), d0) && (!entityplayer.hasEffect(holder) || entityplayer.getEffect(holder).getAmplifier() < mobeffect.getAmplifier() || entityplayer.getEffect(holder).endsWithin(i - 1)); -+ if (condition) { -+ return playerPredicate == null || playerPredicate.test(entityplayer); // Only test the player AFTER it is true -+ } else { -+ return false; -+ } -+ // Paper ned - Add ElderGuardianAppearanceEvent - }); - - list.forEach((entityplayer) -> { -diff --git a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -index 9290f43b4b37a7fa2afae81f8351ea76b7ee7de0..378694a38115c012978e1fea59d049d1ebd04110 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -@@ -67,7 +67,7 @@ public class ElderGuardian extends Guardian { - super.customServerAiStep(world); - if ((this.tickCount + this.getId()) % 1200 == 0) { - MobEffectInstance mobeffect = new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 6000, 2); -- List list = MobEffectUtil.addEffectToPlayersAround(world, this, this.position(), 50.0D, mobeffect, 1200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit -+ List list = MobEffectUtil.addEffectToPlayersAround(world, this, this.position(), 50.0D, mobeffect, 1200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK, (player) -> new io.papermc.paper.event.entity.ElderGuardianAppearanceEvent((org.bukkit.entity.ElderGuardian) this.getBukkitEntity(), player.getBukkitEntity()).callEvent()); // CraftBukkit // Paper - Add ElderGuardianAppearanceEvent - - list.forEach((entityplayer) -> { - entityplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, this.isSilent() ? 0.0F : 1.0F)); diff --git a/patches/server/0543-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch b/patches/server/0543-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch new file mode 100644 index 0000000000..3d03f4c4d2 --- /dev/null +++ b/patches/server/0543-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 12 Sep 2018 21:47:01 -0400 +Subject: [PATCH] Optimize Biome Mob Lookups for Mob Spawning + +Uses an EnumMap as well as a Set paired List for O(1) contains calls. + +diff --git a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java +index d6ebd2ebc3a4a184f1237b00c6c4e709c61d2eec..cb7465ed9bdebe1b31f02d11725e75ff8b44ca66 100644 +--- a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java ++++ b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java +@@ -75,8 +75,40 @@ public class MobSpawnSettings { + } + + public static class Builder { ++ // Paper start - Perf: keep track of data in a pair set to give O(1) contains calls - we have to hook removals incase plugins mess with it ++ public static class MobList extends java.util.ArrayList { ++ java.util.Set biomes = new java.util.HashSet<>(); ++ ++ @Override ++ public boolean contains(Object o) { ++ return biomes.contains(o); ++ } ++ ++ @Override ++ public boolean add(MobSpawnSettings.SpawnerData BiomeSettingsMobs) { ++ biomes.add(BiomeSettingsMobs); ++ return super.add(BiomeSettingsMobs); ++ } ++ ++ @Override ++ public MobSpawnSettings.SpawnerData remove(int index) { ++ MobSpawnSettings.SpawnerData removed = super.remove(index); ++ if (removed != null) { ++ biomes.remove(removed); ++ } ++ return removed; ++ } ++ ++ @Override ++ public void clear() { ++ biomes.clear(); ++ super.clear(); ++ } ++ } ++ // use toImmutableEnumMap collector + private final Map> spawners = Stream.of(MobCategory.values()) +- .collect(ImmutableMap.toImmutableMap(mobCategory -> (MobCategory)mobCategory, mobCategory -> Lists.newArrayList())); ++ .collect(Maps.toImmutableEnumMap(mobCategory -> (MobCategory)mobCategory, mobCategory -> new MobList())); // Use MobList instead of ArrayList ++ // Paper end - Perf: keep track of data in a pair set to give O(1) contains calls + private final Map, MobSpawnSettings.MobSpawnCost> mobSpawnCosts = Maps.newLinkedHashMap(); + private float creatureGenerationProbability = 0.1F; + diff --git a/patches/server/0544-Line-Of-Sight-Changes.patch b/patches/server/0544-Line-Of-Sight-Changes.patch new file mode 100644 index 0000000000..24bc253f3b --- /dev/null +++ b/patches/server/0544-Line-Of-Sight-Changes.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TwoLeggedCat <80929284+TwoLeggedCat@users.noreply.github.com> +Date: Sat, 29 May 2021 14:33:25 -0500 +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 fc51c7ed9b60a307562c81475ef1cedcb1605798..7ee81d5891d9d18566012cd72a516870f529628e 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3913,7 +3913,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, entity.getZ()); + +- return vec3d1.distanceTo(vec3d) > 128.0D ? false : this.level().clip(new ClipContext(vec3d, vec3d1, shapeType, fluidHandling, this)).getType() == HitResult.Type.MISS; ++ // Paper - diff on change - used in CraftLivingEntity#hasLineOfSight(Location) and CraftWorld#lineOfSightExists ++ return vec3d1.distanceToSqr(vec3d) > 128.0D * 128.0D ? false : this.level().clip(new ClipContext(vec3d, vec3d1, shapeType, fluidHandling, this)).getType() == HitResult.Type.MISS; // Paper - Perf: Use distance squared + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +index a070b2a83edaa702b13bc6d3026914126c211576..ca35e93239eea09b3d0dc6ef18f58743e633996b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +@@ -526,5 +526,21 @@ public abstract class CraftRegionAccessor implements RegionAccessor { + public org.bukkit.NamespacedKey getKey() { + return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.getHandle().getLevel().dimension().location()); + } ++ ++ public boolean lineOfSightExists(Location from, Location to) { ++ Preconditions.checkArgument(from != null, "from parameter in lineOfSightExists cannot be null"); ++ Preconditions.checkArgument(to != null, "to parameter in lineOfSightExists cannot be null"); ++ if (from.getWorld() != to.getWorld()) { ++ return false; ++ } ++ ++ net.minecraft.world.phys.Vec3 start = new net.minecraft.world.phys.Vec3(from.getX(), from.getY(), from.getZ()); ++ net.minecraft.world.phys.Vec3 end = new net.minecraft.world.phys.Vec3(to.getX(), to.getY(), to.getZ()); ++ if (end.distanceToSqr(start) > 128D * 128D) { ++ return false; // Return early if the distance is greater than 128 blocks ++ } ++ ++ 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; ++ } + // 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 a4be1eea356ba99358d707381df70032ded42140..a4a30f52f45bf91dc88d53f5d6a376ed739d09eb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -643,6 +643,23 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + return this.getHandle().hasLineOfSight(((CraftEntity) other).getHandle()); + } + ++ // Paper start ++ @Override ++ public boolean hasLineOfSight(Location loc) { ++ if (this.getHandle().level() != ((CraftWorld) loc.getWorld()).getHandle()) { ++ return false; ++ } ++ ++ net.minecraft.world.phys.Vec3 start = new net.minecraft.world.phys.Vec3(this.getHandle().getX(), this.getHandle().getEyeY(), this.getHandle().getZ()); ++ net.minecraft.world.phys.Vec3 end = new net.minecraft.world.phys.Vec3(loc.getX(), loc.getY(), loc.getZ()); ++ if (end.distanceToSqr(start) > 128D * 128D) { ++ return false; // Return early if the distance is greater than 128 blocks ++ } ++ ++ return this.getHandle().level().clipDirect(start, end, net.minecraft.world.phys.shapes.CollisionContext.of(this.getHandle())) == net.minecraft.world.phys.HitResult.Type.MISS; ++ } ++ // Paper end ++ + @Override + public boolean getRemoveWhenFarAway() { + return this.getHandle() instanceof Mob && !((Mob) this.getHandle()).isPersistenceRequired(); diff --git a/patches/server/0544-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch b/patches/server/0544-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch deleted file mode 100644 index 3d03f4c4d2..0000000000 --- a/patches/server/0544-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 12 Sep 2018 21:47:01 -0400 -Subject: [PATCH] Optimize Biome Mob Lookups for Mob Spawning - -Uses an EnumMap as well as a Set paired List for O(1) contains calls. - -diff --git a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java -index d6ebd2ebc3a4a184f1237b00c6c4e709c61d2eec..cb7465ed9bdebe1b31f02d11725e75ff8b44ca66 100644 ---- a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java -+++ b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java -@@ -75,8 +75,40 @@ public class MobSpawnSettings { - } - - public static class Builder { -+ // Paper start - Perf: keep track of data in a pair set to give O(1) contains calls - we have to hook removals incase plugins mess with it -+ public static class MobList extends java.util.ArrayList { -+ java.util.Set biomes = new java.util.HashSet<>(); -+ -+ @Override -+ public boolean contains(Object o) { -+ return biomes.contains(o); -+ } -+ -+ @Override -+ public boolean add(MobSpawnSettings.SpawnerData BiomeSettingsMobs) { -+ biomes.add(BiomeSettingsMobs); -+ return super.add(BiomeSettingsMobs); -+ } -+ -+ @Override -+ public MobSpawnSettings.SpawnerData remove(int index) { -+ MobSpawnSettings.SpawnerData removed = super.remove(index); -+ if (removed != null) { -+ biomes.remove(removed); -+ } -+ return removed; -+ } -+ -+ @Override -+ public void clear() { -+ biomes.clear(); -+ super.clear(); -+ } -+ } -+ // use toImmutableEnumMap collector - private final Map> spawners = Stream.of(MobCategory.values()) -- .collect(ImmutableMap.toImmutableMap(mobCategory -> (MobCategory)mobCategory, mobCategory -> Lists.newArrayList())); -+ .collect(Maps.toImmutableEnumMap(mobCategory -> (MobCategory)mobCategory, mobCategory -> new MobList())); // Use MobList instead of ArrayList -+ // Paper end - Perf: keep track of data in a pair set to give O(1) contains calls - private final Map, MobSpawnSettings.MobSpawnCost> mobSpawnCosts = Maps.newLinkedHashMap(); - private float creatureGenerationProbability = 0.1F; - diff --git a/patches/server/0545-Line-Of-Sight-Changes.patch b/patches/server/0545-Line-Of-Sight-Changes.patch deleted file mode 100644 index 24bc253f3b..0000000000 --- a/patches/server/0545-Line-Of-Sight-Changes.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: TwoLeggedCat <80929284+TwoLeggedCat@users.noreply.github.com> -Date: Sat, 29 May 2021 14:33:25 -0500 -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 fc51c7ed9b60a307562c81475ef1cedcb1605798..7ee81d5891d9d18566012cd72a516870f529628e 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3913,7 +3913,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, entity.getZ()); - -- return vec3d1.distanceTo(vec3d) > 128.0D ? false : this.level().clip(new ClipContext(vec3d, vec3d1, shapeType, fluidHandling, this)).getType() == HitResult.Type.MISS; -+ // Paper - diff on change - used in CraftLivingEntity#hasLineOfSight(Location) and CraftWorld#lineOfSightExists -+ return vec3d1.distanceToSqr(vec3d) > 128.0D * 128.0D ? false : this.level().clip(new ClipContext(vec3d, vec3d1, shapeType, fluidHandling, this)).getType() == HitResult.Type.MISS; // Paper - Perf: Use distance squared - } - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -index a070b2a83edaa702b13bc6d3026914126c211576..ca35e93239eea09b3d0dc6ef18f58743e633996b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java -@@ -526,5 +526,21 @@ public abstract class CraftRegionAccessor implements RegionAccessor { - public org.bukkit.NamespacedKey getKey() { - return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.getHandle().getLevel().dimension().location()); - } -+ -+ public boolean lineOfSightExists(Location from, Location to) { -+ Preconditions.checkArgument(from != null, "from parameter in lineOfSightExists cannot be null"); -+ Preconditions.checkArgument(to != null, "to parameter in lineOfSightExists cannot be null"); -+ if (from.getWorld() != to.getWorld()) { -+ return false; -+ } -+ -+ net.minecraft.world.phys.Vec3 start = new net.minecraft.world.phys.Vec3(from.getX(), from.getY(), from.getZ()); -+ net.minecraft.world.phys.Vec3 end = new net.minecraft.world.phys.Vec3(to.getX(), to.getY(), to.getZ()); -+ if (end.distanceToSqr(start) > 128D * 128D) { -+ return false; // Return early if the distance is greater than 128 blocks -+ } -+ -+ 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; -+ } - // 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 a4be1eea356ba99358d707381df70032ded42140..a4a30f52f45bf91dc88d53f5d6a376ed739d09eb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -643,6 +643,23 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - return this.getHandle().hasLineOfSight(((CraftEntity) other).getHandle()); - } - -+ // Paper start -+ @Override -+ public boolean hasLineOfSight(Location loc) { -+ if (this.getHandle().level() != ((CraftWorld) loc.getWorld()).getHandle()) { -+ return false; -+ } -+ -+ net.minecraft.world.phys.Vec3 start = new net.minecraft.world.phys.Vec3(this.getHandle().getX(), this.getHandle().getEyeY(), this.getHandle().getZ()); -+ net.minecraft.world.phys.Vec3 end = new net.minecraft.world.phys.Vec3(loc.getX(), loc.getY(), loc.getZ()); -+ if (end.distanceToSqr(start) > 128D * 128D) { -+ return false; // Return early if the distance is greater than 128 blocks -+ } -+ -+ return this.getHandle().level().clipDirect(start, end, net.minecraft.world.phys.shapes.CollisionContext.of(this.getHandle())) == net.minecraft.world.phys.HitResult.Type.MISS; -+ } -+ // Paper end -+ - @Override - public boolean getRemoveWhenFarAway() { - return this.getHandle() instanceof Mob && !((Mob) this.getHandle()).isPersistenceRequired(); diff --git a/patches/server/0545-add-per-world-spawn-limits.patch b/patches/server/0545-add-per-world-spawn-limits.patch new file mode 100644 index 0000000000..6ed4ae68af --- /dev/null +++ b/patches/server/0545-add-per-world-spawn-limits.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chase +Date: Wed, 2 Dec 2020 22:43:39 -0800 +Subject: [PATCH] add per world spawn limits + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 691d65bca79d503a43f696d92a0a32226cddaad5..d72ceb866f8632a8daa7dc19acdc57b6b78fd906 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -219,6 +219,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { + this.biomeProvider = biomeProvider; + + this.environment = env; ++ // Paper start - per world spawn limits ++ for (SpawnCategory spawnCategory : SpawnCategory.values()) { ++ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { ++ setSpawnLimit(spawnCategory, this.world.paperConfig().entities.spawning.spawnLimits.getInt(CraftSpawnCategory.toNMS(spawnCategory))); ++ } ++ } ++ // Paper end - per world spawn limits + } + + @Override diff --git a/patches/server/0546-Fix-potions-splash-events.patch b/patches/server/0546-Fix-potions-splash-events.patch new file mode 100644 index 0000000000..68350d52f2 --- /dev/null +++ b/patches/server/0546-Fix-potions-splash-events.patch @@ -0,0 +1,181 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 20 May 2021 20:40:53 -0700 +Subject: [PATCH] Fix potions splash events + +Fix PotionSplashEvent for water splash potions +Fixes SPIGOT-6221: https://hub.spigotmc.org/jira/projects/SPIGOT/issues/SPIGOT-6221 +Fix splash events cancellation that still show particles/sound + +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 224e768963d6969f25608065d37ad72d82acda68..d6ac07d9d5ee0430a1d91b7084b378aac1d047e5 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java +@@ -109,55 +109,76 @@ public class ThrownPotion extends ThrowableItemProjectile { + ItemStack itemstack = this.getItem(); + PotionContents potioncontents = (PotionContents) itemstack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); + ++ boolean showParticles = true; // Paper - Fix potions splash events + if (potioncontents.is(Potions.WATER)) { +- this.applyWater(worldserver); ++ showParticles = this.applyWater(worldserver, hitResult); // Paper - Fix potions splash events + } else if (true || potioncontents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply + if (this.isLingering()) { +- this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition ++ showParticles = this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper + } else { +- this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition ++ showParticles = this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper + } + } + ++ if (showParticles) { // Paper - Fix potions splash events + int i = potioncontents.potion().isPresent() && ((Potion) ((Holder) potioncontents.potion().get()).value()).hasInstantEffects() ? 2007 : 2002; + + worldserver.levelEvent(i, this.blockPosition(), potioncontents.getColor()); ++ } // Paper - Fix potions splash events + this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } + +- private void applyWater(ServerLevel world) { ++ private static final Predicate APPLY_WATER_GET_ENTITIES_PREDICATE = ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE.or(Axolotl.class::isInstance); // Paper - Fix potions splash events ++ private boolean applyWater(ServerLevel world, @Nullable HitResult hitResult) { // Paper - Fix potions splash events + AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); +- List list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE); ++ // Paper start - Fix potions splash events ++ List list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.APPLY_WATER_GET_ENTITIES_PREDICATE); ++ Map affected = new HashMap<>(); ++ java.util.Set rehydrate = new java.util.HashSet<>(); ++ java.util.Set extinguish = new java.util.HashSet<>(); + Iterator iterator = list.iterator(); + + while (iterator.hasNext()) { + net.minecraft.world.entity.LivingEntity entityliving = (net.minecraft.world.entity.LivingEntity) iterator.next(); ++ if (entityliving instanceof Axolotl axolotl) { ++ rehydrate.add(((org.bukkit.entity.Axolotl) axolotl.getBukkitEntity())); ++ } + double d0 = this.distanceToSqr((Entity) entityliving); + + if (d0 < 16.0D) { + if (entityliving.isSensitiveToWater()) { +- entityliving.hurtServer(world, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); ++ affected.put(entityliving.getBukkitLivingEntity(), 1.0); + } + + if (entityliving.isOnFire() && entityliving.isAlive()) { +- entityliving.extinguishFire(); ++ extinguish.add(entityliving.getBukkitLivingEntity()); + } + } + } + +- List list1 = this.level().getEntitiesOfClass(Axolotl.class, axisalignedbb); +- Iterator iterator1 = list1.iterator(); +- +- while (iterator1.hasNext()) { +- Axolotl axolotl = (Axolotl) iterator1.next(); +- +- axolotl.rehydrate(); ++ io.papermc.paper.event.entity.WaterBottleSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callWaterBottleSplashEvent( ++ this, hitResult, affected, rehydrate, extinguish ++ ); ++ if (!event.isCancelled()) { ++ for (LivingEntity affectedEntity : event.getToDamage()) { ++ ((CraftLivingEntity) affectedEntity).getHandle().hurtServer(world, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); ++ } ++ for (LivingEntity toExtinguish : event.getToExtinguish()) { ++ ((CraftLivingEntity) toExtinguish).getHandle().extinguishFire(); ++ } ++ for (LivingEntity toRehydrate : event.getToRehydrate()) { ++ if (((CraftLivingEntity) toRehydrate).getHandle() instanceof Axolotl axolotl) { ++ axolotl.rehydrate(); ++ } ++ } ++ // Paper end - Fix potions splash events + } ++ return !event.isCancelled(); // Paper - Fix potions splash events + + } + +- private void applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition ++ private boolean applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events + 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 +@@ -175,6 +196,7 @@ public class ThrownPotion extends ThrowableItemProjectile { + if (d0 < 16.0D) { + double d1; + ++ // Paper - diff on change, used when calling the splash event for water splash potions + if (entityliving == entity) { + d1 = 1.0D; + } else { +@@ -230,10 +252,11 @@ public class ThrownPotion extends ThrowableItemProjectile { + } + } + } ++ return !event.isCancelled(); // Paper - Fix potions splash events + + } + +- private void makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition ++ private boolean makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition + AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); + Entity entity = this.getOwner(); + +@@ -246,14 +269,16 @@ public class ThrownPotion extends ThrowableItemProjectile { + entityareaeffectcloud.setWaitTime(10); + entityareaeffectcloud.setRadiusPerTick(-entityareaeffectcloud.getRadius() / (float) entityareaeffectcloud.getDuration()); + entityareaeffectcloud.setPotionContents(potioncontents); ++ 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())) { ++ 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 + this.level().addFreshEntity(entityareaeffectcloud); + } else { + entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause + } + // CraftBukkit end ++ return !event.isCancelled(); // Paper - Fix potions splash events + } + + public boolean isLingering() { +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 49efae40345fcfca8f80fcc541dcfde1b8a8b07b..24f86724012bb8bcd6d24683a1c78ce66b42ca30 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -884,6 +884,32 @@ public class CraftEventFactory { + return event; + } + ++ // Paper start - Fix potions splash events ++ public static io.papermc.paper.event.entity.WaterBottleSplashEvent callWaterBottleSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult hitResult, Map affectedEntities, java.util.Set rehydrate, java.util.Set extinguish) { ++ ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity(); ++ ++ Block hitBlock = null; ++ BlockFace hitFace = null; ++ org.bukkit.entity.Entity hitEntity = null; ++ ++ if (hitResult != null) { ++ if (hitResult.getType() == HitResult.Type.BLOCK) { ++ BlockHitResult blockHitResult = (BlockHitResult) hitResult; ++ hitBlock = CraftBlock.at(potion.level(), blockHitResult.getBlockPos()); ++ hitFace = CraftBlock.notchToBlockFace(blockHitResult.getDirection()); ++ } else if (hitResult.getType() == HitResult.Type.ENTITY) { ++ hitEntity = ((EntityHitResult) hitResult).getEntity().getBukkitEntity(); ++ } ++ } ++ ++ io.papermc.paper.event.entity.WaterBottleSplashEvent event = new io.papermc.paper.event.entity.WaterBottleSplashEvent( ++ thrownPotion, hitEntity, hitBlock, hitFace, affectedEntities, rehydrate, extinguish ++ ); ++ event.callEvent(); ++ return event; ++ } ++ // Paper end - Fix potions splash events ++ + /** + * BlockFadeEvent + */ diff --git a/patches/server/0546-add-per-world-spawn-limits.patch b/patches/server/0546-add-per-world-spawn-limits.patch deleted file mode 100644 index 6ed4ae68af..0000000000 --- a/patches/server/0546-add-per-world-spawn-limits.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: chase -Date: Wed, 2 Dec 2020 22:43:39 -0800 -Subject: [PATCH] add per world spawn limits - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 691d65bca79d503a43f696d92a0a32226cddaad5..d72ceb866f8632a8daa7dc19acdc57b6b78fd906 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -219,6 +219,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { - this.biomeProvider = biomeProvider; - - this.environment = env; -+ // Paper start - per world spawn limits -+ for (SpawnCategory spawnCategory : SpawnCategory.values()) { -+ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { -+ setSpawnLimit(spawnCategory, this.world.paperConfig().entities.spawning.spawnLimits.getInt(CraftSpawnCategory.toNMS(spawnCategory))); -+ } -+ } -+ // Paper end - per world spawn limits - } - - @Override diff --git a/patches/server/0547-Add-more-LimitedRegion-API.patch b/patches/server/0547-Add-more-LimitedRegion-API.patch new file mode 100644 index 0000000000..f46a2383c8 --- /dev/null +++ b/patches/server/0547-Add-more-LimitedRegion-API.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dfsek +Date: Sat, 19 Jun 2021 20:15:59 -0700 +Subject: [PATCH] Add more LimitedRegion API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java +index ca250dba422f8092b99f72b322147061a7541d14..2c7b64bd7071cb803a042152d497982d753e0b5d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java ++++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java +@@ -255,4 +255,45 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe + public void addEntityWithPassengers(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason) { + this.entities.add(entity); + } ++ ++ // Paper start - Add more LimitedRegion API ++ @Override ++ public void setBlockState(int x, int y, int z, BlockState state) { ++ BlockPos pos = new BlockPos(x, y, z); ++ if (!state.getBlockData().matches(getHandle().getBlockState(pos).createCraftBlockData())) { ++ throw new IllegalArgumentException("BlockData does not match! Expected " + state.getBlockData().getAsString(false) + ", got " + getHandle().getBlockState(pos).createCraftBlockData().getAsString(false)); ++ } ++ getHandle().getBlockEntity(pos).loadWithComponents(((org.bukkit.craftbukkit.block.CraftBlockEntityState) state).getSnapshotNBT(), this.getHandle().registryAccess()); ++ } ++ ++ @Override ++ public void scheduleBlockUpdate(int x, int y, int z) { ++ BlockPos position = new BlockPos(x, y, z); ++ getHandle().scheduleTick(position, getHandle().getBlockState(position).getBlock(), 0); ++ } ++ ++ @Override ++ public void scheduleFluidUpdate(int x, int y, int z) { ++ BlockPos position = new BlockPos(x, y, z); ++ getHandle().scheduleTick(position, getHandle().getFluidState(position).getType(), 0); ++ } ++ ++ @Override ++ public World getWorld() { ++ // reading/writing the returned Minecraft world causes a deadlock. ++ // By implementing this, and covering it in warnings, we're assuming people won't be stupid, and ++ // if they are stupid, they'll figure it out pretty fast. ++ return getHandle().getMinecraftWorld().getWorld(); ++ } ++ ++ @Override ++ public int getCenterChunkX() { ++ return centerChunkX; ++ } ++ ++ @Override ++ public int getCenterChunkZ() { ++ return centerChunkZ; ++ } ++ // Paper end - Add more LimitedRegion API + } diff --git a/patches/server/0547-Fix-potions-splash-events.patch b/patches/server/0547-Fix-potions-splash-events.patch deleted file mode 100644 index 68350d52f2..0000000000 --- a/patches/server/0547-Fix-potions-splash-events.patch +++ /dev/null @@ -1,181 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 20 May 2021 20:40:53 -0700 -Subject: [PATCH] Fix potions splash events - -Fix PotionSplashEvent for water splash potions -Fixes SPIGOT-6221: https://hub.spigotmc.org/jira/projects/SPIGOT/issues/SPIGOT-6221 -Fix splash events cancellation that still show particles/sound - -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 224e768963d6969f25608065d37ad72d82acda68..d6ac07d9d5ee0430a1d91b7084b378aac1d047e5 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java -@@ -109,55 +109,76 @@ public class ThrownPotion extends ThrowableItemProjectile { - ItemStack itemstack = this.getItem(); - PotionContents potioncontents = (PotionContents) itemstack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); - -+ boolean showParticles = true; // Paper - Fix potions splash events - if (potioncontents.is(Potions.WATER)) { -- this.applyWater(worldserver); -+ showParticles = this.applyWater(worldserver, hitResult); // Paper - Fix potions splash events - } else if (true || potioncontents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply - if (this.isLingering()) { -- this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition -+ showParticles = this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper - } else { -- this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition -+ showParticles = this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper - } - } - -+ if (showParticles) { // Paper - Fix potions splash events - int i = potioncontents.potion().isPresent() && ((Potion) ((Holder) potioncontents.potion().get()).value()).hasInstantEffects() ? 2007 : 2002; - - worldserver.levelEvent(i, this.blockPosition(), potioncontents.getColor()); -+ } // Paper - Fix potions splash events - this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause - } - } - -- private void applyWater(ServerLevel world) { -+ private static final Predicate APPLY_WATER_GET_ENTITIES_PREDICATE = ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE.or(Axolotl.class::isInstance); // Paper - Fix potions splash events -+ private boolean applyWater(ServerLevel world, @Nullable HitResult hitResult) { // Paper - Fix potions splash events - AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); -- List list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE); -+ // Paper start - Fix potions splash events -+ List list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.APPLY_WATER_GET_ENTITIES_PREDICATE); -+ Map affected = new HashMap<>(); -+ java.util.Set rehydrate = new java.util.HashSet<>(); -+ java.util.Set extinguish = new java.util.HashSet<>(); - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { - net.minecraft.world.entity.LivingEntity entityliving = (net.minecraft.world.entity.LivingEntity) iterator.next(); -+ if (entityliving instanceof Axolotl axolotl) { -+ rehydrate.add(((org.bukkit.entity.Axolotl) axolotl.getBukkitEntity())); -+ } - double d0 = this.distanceToSqr((Entity) entityliving); - - if (d0 < 16.0D) { - if (entityliving.isSensitiveToWater()) { -- entityliving.hurtServer(world, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); -+ affected.put(entityliving.getBukkitLivingEntity(), 1.0); - } - - if (entityliving.isOnFire() && entityliving.isAlive()) { -- entityliving.extinguishFire(); -+ extinguish.add(entityliving.getBukkitLivingEntity()); - } - } - } - -- List list1 = this.level().getEntitiesOfClass(Axolotl.class, axisalignedbb); -- Iterator iterator1 = list1.iterator(); -- -- while (iterator1.hasNext()) { -- Axolotl axolotl = (Axolotl) iterator1.next(); -- -- axolotl.rehydrate(); -+ io.papermc.paper.event.entity.WaterBottleSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callWaterBottleSplashEvent( -+ this, hitResult, affected, rehydrate, extinguish -+ ); -+ if (!event.isCancelled()) { -+ for (LivingEntity affectedEntity : event.getToDamage()) { -+ ((CraftLivingEntity) affectedEntity).getHandle().hurtServer(world, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); -+ } -+ for (LivingEntity toExtinguish : event.getToExtinguish()) { -+ ((CraftLivingEntity) toExtinguish).getHandle().extinguishFire(); -+ } -+ for (LivingEntity toRehydrate : event.getToRehydrate()) { -+ if (((CraftLivingEntity) toRehydrate).getHandle() instanceof Axolotl axolotl) { -+ axolotl.rehydrate(); -+ } -+ } -+ // Paper end - Fix potions splash events - } -+ return !event.isCancelled(); // Paper - Fix potions splash events - - } - -- private void applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition -+ private boolean applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events - 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 -@@ -175,6 +196,7 @@ public class ThrownPotion extends ThrowableItemProjectile { - if (d0 < 16.0D) { - double d1; - -+ // Paper - diff on change, used when calling the splash event for water splash potions - if (entityliving == entity) { - d1 = 1.0D; - } else { -@@ -230,10 +252,11 @@ public class ThrownPotion extends ThrowableItemProjectile { - } - } - } -+ return !event.isCancelled(); // Paper - Fix potions splash events - - } - -- private void makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition -+ private boolean makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition - AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); - Entity entity = this.getOwner(); - -@@ -246,14 +269,16 @@ public class ThrownPotion extends ThrowableItemProjectile { - entityareaeffectcloud.setWaitTime(10); - entityareaeffectcloud.setRadiusPerTick(-entityareaeffectcloud.getRadius() / (float) entityareaeffectcloud.getDuration()); - entityareaeffectcloud.setPotionContents(potioncontents); -+ 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())) { -+ 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 - this.level().addFreshEntity(entityareaeffectcloud); - } else { - entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause - } - // CraftBukkit end -+ return !event.isCancelled(); // Paper - Fix potions splash events - } - - public boolean isLingering() { -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 49efae40345fcfca8f80fcc541dcfde1b8a8b07b..24f86724012bb8bcd6d24683a1c78ce66b42ca30 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -884,6 +884,32 @@ public class CraftEventFactory { - return event; - } - -+ // Paper start - Fix potions splash events -+ public static io.papermc.paper.event.entity.WaterBottleSplashEvent callWaterBottleSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult hitResult, Map affectedEntities, java.util.Set rehydrate, java.util.Set extinguish) { -+ ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity(); -+ -+ Block hitBlock = null; -+ BlockFace hitFace = null; -+ org.bukkit.entity.Entity hitEntity = null; -+ -+ if (hitResult != null) { -+ if (hitResult.getType() == HitResult.Type.BLOCK) { -+ BlockHitResult blockHitResult = (BlockHitResult) hitResult; -+ hitBlock = CraftBlock.at(potion.level(), blockHitResult.getBlockPos()); -+ hitFace = CraftBlock.notchToBlockFace(blockHitResult.getDirection()); -+ } else if (hitResult.getType() == HitResult.Type.ENTITY) { -+ hitEntity = ((EntityHitResult) hitResult).getEntity().getBukkitEntity(); -+ } -+ } -+ -+ io.papermc.paper.event.entity.WaterBottleSplashEvent event = new io.papermc.paper.event.entity.WaterBottleSplashEvent( -+ thrownPotion, hitEntity, hitBlock, hitFace, affectedEntities, rehydrate, extinguish -+ ); -+ event.callEvent(); -+ return event; -+ } -+ // Paper end - Fix potions splash events -+ - /** - * BlockFadeEvent - */ diff --git a/patches/server/0548-Add-more-LimitedRegion-API.patch b/patches/server/0548-Add-more-LimitedRegion-API.patch deleted file mode 100644 index f46a2383c8..0000000000 --- a/patches/server/0548-Add-more-LimitedRegion-API.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: dfsek -Date: Sat, 19 Jun 2021 20:15:59 -0700 -Subject: [PATCH] Add more LimitedRegion API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java -index ca250dba422f8092b99f72b322147061a7541d14..2c7b64bd7071cb803a042152d497982d753e0b5d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java -+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java -@@ -255,4 +255,45 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe - public void addEntityWithPassengers(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason) { - this.entities.add(entity); - } -+ -+ // Paper start - Add more LimitedRegion API -+ @Override -+ public void setBlockState(int x, int y, int z, BlockState state) { -+ BlockPos pos = new BlockPos(x, y, z); -+ if (!state.getBlockData().matches(getHandle().getBlockState(pos).createCraftBlockData())) { -+ throw new IllegalArgumentException("BlockData does not match! Expected " + state.getBlockData().getAsString(false) + ", got " + getHandle().getBlockState(pos).createCraftBlockData().getAsString(false)); -+ } -+ getHandle().getBlockEntity(pos).loadWithComponents(((org.bukkit.craftbukkit.block.CraftBlockEntityState) state).getSnapshotNBT(), this.getHandle().registryAccess()); -+ } -+ -+ @Override -+ public void scheduleBlockUpdate(int x, int y, int z) { -+ BlockPos position = new BlockPos(x, y, z); -+ getHandle().scheduleTick(position, getHandle().getBlockState(position).getBlock(), 0); -+ } -+ -+ @Override -+ public void scheduleFluidUpdate(int x, int y, int z) { -+ BlockPos position = new BlockPos(x, y, z); -+ getHandle().scheduleTick(position, getHandle().getFluidState(position).getType(), 0); -+ } -+ -+ @Override -+ public World getWorld() { -+ // reading/writing the returned Minecraft world causes a deadlock. -+ // By implementing this, and covering it in warnings, we're assuming people won't be stupid, and -+ // if they are stupid, they'll figure it out pretty fast. -+ return getHandle().getMinecraftWorld().getWorld(); -+ } -+ -+ @Override -+ public int getCenterChunkX() { -+ return centerChunkX; -+ } -+ -+ @Override -+ public int getCenterChunkZ() { -+ return centerChunkZ; -+ } -+ // Paper end - Add more LimitedRegion API - } diff --git a/patches/server/0548-Fix-PlayerDropItemEvent-using-wrong-item.patch b/patches/server/0548-Fix-PlayerDropItemEvent-using-wrong-item.patch new file mode 100644 index 0000000000..c5e9aa8056 --- /dev/null +++ b/patches/server/0548-Fix-PlayerDropItemEvent-using-wrong-item.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 20 Jun 2021 21:55:59 -0700 +Subject: [PATCH] Fix PlayerDropItemEvent using wrong item + + +diff --git a/src/main/java/net/minecraft/server/commands/GiveCommand.java b/src/main/java/net/minecraft/server/commands/GiveCommand.java +index c81fd3e1108fb0a02f9240263404af2b968c8494..0d9de4c61c7b26a6ff37c12fde629161fd0c3d5a 100644 +--- a/src/main/java/net/minecraft/server/commands/GiveCommand.java ++++ b/src/main/java/net/minecraft/server/commands/GiveCommand.java +@@ -38,6 +38,7 @@ public class GiveCommand { + + private static int giveItem(CommandSourceStack source, ItemInput item, Collection targets, int count) throws CommandSyntaxException { + ItemStack itemstack = item.createItemStack(1, false); ++ final Component displayName = itemstack.getDisplayName(); // Paper - get display name early + int j = itemstack.getMaxStackSize(); + int k = j * 100; + +@@ -79,11 +80,11 @@ public class GiveCommand { + + if (targets.size() == 1) { + source.sendSuccess(() -> { +- return Component.translatable("commands.give.success.single", count, itemstack.getDisplayName(), ((ServerPlayer) targets.iterator().next()).getDisplayName()); ++ return Component.translatable("commands.give.success.single", count, displayName, ((ServerPlayer) targets.iterator().next()).getDisplayName()); // Paper - use cached display name + }, true); + } else { + source.sendSuccess(() -> { +- return Component.translatable("commands.give.success.single", count, itemstack.getDisplayName(), targets.size()); ++ return Component.translatable("commands.give.success.single", count, displayName, targets.size()); // Paper - use cached display name + }, true); + } + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 32fc24fa05660ff941fc02bb3c1827790acbbb1a..33974faafabe763ac7d932f2fdb814ea914ccf88 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -2724,7 +2724,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + + if (flag1) { + if (!itemstack1.isEmpty()) { +- this.awardStat(Stats.ITEM_DROPPED.get(itemstack1.getItem()), itemstack.getCount()); ++ this.awardStat(Stats.ITEM_DROPPED.get(itemstack1.getItem()), itemstack1.getCount()); // Paper - Fix PlayerDropItemEvent using wrong item + } + + this.awardStat(Stats.DROP); +@@ -2740,6 +2740,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + return null; + } else { + double d0 = this.getEyeY() - 0.30000001192092896D; ++ // Paper start ++ ItemStack tmp = stack.copy(); ++ stack.setCount(0); ++ stack = tmp; ++ // Paper end + ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), d0, this.getZ(), stack); + + entityitem.setPickUpDelay(40); diff --git a/patches/server/0549-Fix-PlayerDropItemEvent-using-wrong-item.patch b/patches/server/0549-Fix-PlayerDropItemEvent-using-wrong-item.patch deleted file mode 100644 index 6fbcb401ee..0000000000 --- a/patches/server/0549-Fix-PlayerDropItemEvent-using-wrong-item.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 20 Jun 2021 21:55:59 -0700 -Subject: [PATCH] Fix PlayerDropItemEvent using wrong item - - -diff --git a/src/main/java/net/minecraft/server/commands/GiveCommand.java b/src/main/java/net/minecraft/server/commands/GiveCommand.java -index c81fd3e1108fb0a02f9240263404af2b968c8494..0d9de4c61c7b26a6ff37c12fde629161fd0c3d5a 100644 ---- a/src/main/java/net/minecraft/server/commands/GiveCommand.java -+++ b/src/main/java/net/minecraft/server/commands/GiveCommand.java -@@ -38,6 +38,7 @@ public class GiveCommand { - - private static int giveItem(CommandSourceStack source, ItemInput item, Collection targets, int count) throws CommandSyntaxException { - ItemStack itemstack = item.createItemStack(1, false); -+ final Component displayName = itemstack.getDisplayName(); // Paper - get display name early - int j = itemstack.getMaxStackSize(); - int k = j * 100; - -@@ -79,11 +80,11 @@ public class GiveCommand { - - if (targets.size() == 1) { - source.sendSuccess(() -> { -- return Component.translatable("commands.give.success.single", count, itemstack.getDisplayName(), ((ServerPlayer) targets.iterator().next()).getDisplayName()); -+ return Component.translatable("commands.give.success.single", count, displayName, ((ServerPlayer) targets.iterator().next()).getDisplayName()); // Paper - use cached display name - }, true); - } else { - source.sendSuccess(() -> { -- return Component.translatable("commands.give.success.single", count, itemstack.getDisplayName(), targets.size()); -+ return Component.translatable("commands.give.success.single", count, displayName, targets.size()); // Paper - use cached display name - }, true); - } - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 2125f9dc87dbf31a66004dc859788f584e099e73..b1224b0ef12a746477047073f5bb94405871ce85 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -2724,7 +2724,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - - if (flag1) { - if (!itemstack1.isEmpty()) { -- this.awardStat(Stats.ITEM_DROPPED.get(itemstack1.getItem()), itemstack.getCount()); -+ this.awardStat(Stats.ITEM_DROPPED.get(itemstack1.getItem()), itemstack1.getCount()); // Paper - Fix PlayerDropItemEvent using wrong item - } - - this.awardStat(Stats.DROP); -@@ -2740,6 +2740,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - return null; - } else { - double d0 = this.getEyeY() - 0.30000001192092896D; -+ // Paper start -+ ItemStack tmp = stack.copy(); -+ stack.setCount(0); -+ stack = tmp; -+ // Paper end - ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), d0, this.getZ(), stack); - - entityitem.setPickUpDelay(40); diff --git a/patches/server/0549-Missing-Entity-API.patch b/patches/server/0549-Missing-Entity-API.patch new file mode 100644 index 0000000000..72a11a4b7e --- /dev/null +++ b/patches/server/0549-Missing-Entity-API.patch @@ -0,0 +1,1402 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Mon, 21 Jun 2021 23:56:07 -0400 +Subject: [PATCH] Missing Entity API + +== AT == +public net.minecraft.world.entity.animal.Fox isDefending()Z +public net.minecraft.world.entity.animal.Fox setDefending(Z)V +public net.minecraft.world.entity.animal.Fox setFaceplanted(Z)V +public net.minecraft.world.entity.animal.Panda getEatCounter()I +public net.minecraft.world.entity.animal.Panda setEatCounter(I)V +public net.minecraft.world.entity.animal.Bee isRolling()Z +public net.minecraft.world.entity.animal.Bee setRolling(Z)V +public net.minecraft.world.entity.animal.Bee numCropsGrownSincePollination +public net.minecraft.world.entity.animal.Bee ticksWithoutNectarSinceExitingHive +public net.minecraft.world.entity.monster.piglin.Piglin isChargingCrossbow()Z +public net.minecraft.world.entity.ambient.Bat targetPosition +public net.minecraft.world.entity.monster.Ravager attackTick +public net.minecraft.world.entity.monster.Ravager stunnedTick +public net.minecraft.world.entity.monster.Ravager roarTick +public net.minecraft.world.entity.vehicle.MinecartTNT explode(D)V +public net.minecraft.world.entity.vehicle.MinecartTNT fuse +public net.minecraft.world.entity.monster.Endermite life +public net.minecraft.world.entity.projectile.AbstractArrow soundEvent +public net.minecraft.world.entity.monster.Phantom anchorPoint +public net.minecraft.world.entity.npc.WanderingTrader getWanderTarget()Lnet/minecraft/core/BlockPos; +public net.minecraft.world.entity.animal.AbstractSchoolingFish leader +public net.minecraft.world.entity.animal.AbstractSchoolingFish schoolSize +public net.minecraft.world.entity.animal.Rabbit moreCarrotTicks +public net.minecraft.world.entity.AreaEffectCloud ownerUUID +public net.minecraft.world.entity.animal.MushroomCow stewEffects +public net.minecraft.world.entity.Entity FLAG_INVISIBLE +public net.minecraft.world.entity.animal.Cat setRelaxStateOne(Z)V +public net.minecraft.world.entity.animal.Cat isRelaxStateOne()Z + +Co-authored-by: Nassim Jahnke +Co-authored-by: Jake Potrebic +Co-authored-by: William Blake Galbreath +Co-authored-by: SoSeDiK +Co-authored-by: booky10 +Co-authored-by: Amin +Co-authored-by: TrollyLoki +Co-authored-by: FireInstall +Co-authored-by: maxcom1 <46265094+maxcom1@users.noreply.github.com> +Co-authored-by: TotalledZebra + +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +index 99d0118061233eced90ca5aed2eb5ff0b188837b..6bdc683b5ade408ee27f1d6636b4d60c8c89cb7c 100644 +--- a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +@@ -164,7 +164,7 @@ public class MobGoalHelper { + bukkitMap.put(net.minecraft.world.entity.monster.Endermite.class, Endermite.class); + bukkitMap.put(net.minecraft.world.entity.monster.Evoker.class, Evoker.class); + bukkitMap.put(AbstractFish.class, Fish.class); +- bukkitMap.put(AbstractSchoolingFish.class, Fish.class); // close enough ++ bukkitMap.put(AbstractSchoolingFish.class, io.papermc.paper.entity.SchoolableFish.class); + bukkitMap.put(FlyingMob.class, Flying.class); + bukkitMap.put(net.minecraft.world.entity.animal.Fox.class, Fox.class); + bukkitMap.put(net.minecraft.world.entity.monster.Ghast.class, Ghast.class); +diff --git a/src/main/java/io/papermc/paper/entity/PaperSchoolableFish.java b/src/main/java/io/papermc/paper/entity/PaperSchoolableFish.java +new file mode 100644 +index 0000000000000000000000000000000000000000..41bf71d116ffc5431586ce54abba7f8def6c1dcf +--- /dev/null ++++ b/src/main/java/io/papermc/paper/entity/PaperSchoolableFish.java +@@ -0,0 +1,52 @@ ++package io.papermc.paper.entity; ++ ++import net.minecraft.world.entity.animal.AbstractSchoolingFish; ++import org.bukkit.craftbukkit.CraftServer; ++import org.bukkit.craftbukkit.entity.CraftFish; ++import org.jetbrains.annotations.NotNull; ++ ++public class PaperSchoolableFish extends CraftFish implements SchoolableFish { ++ ++ public PaperSchoolableFish(CraftServer server, AbstractSchoolingFish entity) { ++ super(server, entity); ++ } ++ ++ @Override ++ public AbstractSchoolingFish getHandle() { ++ return (AbstractSchoolingFish) super.getHandle(); ++ } ++ ++ @Override ++ public void startFollowing(@NotNull SchoolableFish fish) { ++ if (this.getHandle().isFollower()) { // If following a fish already, properly remove the old one ++ this.stopFollowing(); ++ } ++ ++ this.getHandle().startFollowing(((PaperSchoolableFish) fish).getHandle()); ++ } ++ ++ @Override ++ public void stopFollowing() { ++ this.getHandle().stopFollowing(); ++ } ++ ++ @Override ++ public int getSchoolSize() { ++ return this.getHandle().schoolSize; ++ } ++ ++ @Override ++ public int getMaxSchoolSize() { ++ return this.getHandle().getMaxSchoolSize(); ++ } ++ ++ @Override ++ public SchoolableFish getSchoolLeader() { ++ AbstractSchoolingFish leader = this.getHandle().leader; ++ if (leader == null) { ++ return null; ++ } ++ ++ return (SchoolableFish) leader.getBukkitEntity(); ++ } ++} +diff --git a/src/main/java/net/minecraft/world/entity/animal/AbstractSchoolingFish.java b/src/main/java/net/minecraft/world/entity/animal/AbstractSchoolingFish.java +index 30095df7b64cfda4931dbfa22549ff5abefd53e0..c8ae49f58c254119c0e64a4e1501ebc5a70f9a46 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/AbstractSchoolingFish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/AbstractSchoolingFish.java +@@ -51,6 +51,7 @@ public abstract class AbstractSchoolingFish extends AbstractFish { + } + + public void stopFollowing() { ++ if (this.leader == null) return; // Avoid NPE, plugins can now set the leader and certain fish goals might cause this method to be called + this.leader.removeFollower(); + this.leader = null; + } +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 a48a29b5b1963db679b053f3530f64d2b9560290..a5eab5cdb761e3e9d37ea66287f26a2c3345182d 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java +@@ -565,11 +565,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + this.setFlag(4, hasStung); + } + ++ public net.kyori.adventure.util.TriState rollingOverride = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Rolling override + public boolean isRolling() { + return this.getFlag(2); + } + + public void setRolling(boolean nearTarget) { ++ nearTarget = rollingOverride.toBooleanOrElse(nearTarget); // Paper - Rolling override + this.setFlag(2, nearTarget); + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java +index b9d7aa4aa0fc3472a2a0700e526778daf62bdc6f..48ac8c3f6e00c3c2dc67b6c994be7c0ac6dfcf81 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java ++++ b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java +@@ -50,6 +50,7 @@ public class Tadpole extends AbstractFish { + public int age; + protected static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.HURT_BY, SensorType.FROG_TEMPTATIONS); + protected static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.LOOK_TARGET, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.NEAREST_VISIBLE_ADULT, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.BREED_TARGET, MemoryModuleType.IS_PANICKING); ++ public boolean ageLocked; // Paper + + public Tadpole(EntityType type, Level world) { + super(type, world); +@@ -102,7 +103,7 @@ public class Tadpole extends AbstractFish { + @Override + public void aiStep() { + super.aiStep(); +- if (!this.level().isClientSide) { ++ if (!this.level().isClientSide && !this.ageLocked) { // Paper + this.setAge(this.age + 1); + } + +@@ -112,12 +113,14 @@ public class Tadpole extends AbstractFish { + public void addAdditionalSaveData(CompoundTag nbt) { + super.addAdditionalSaveData(nbt); + nbt.putInt("Age", this.age); ++ nbt.putBoolean("AgeLocked", this.ageLocked); // Paper + } + + @Override + public void readAdditionalSaveData(CompoundTag nbt) { + super.readAdditionalSaveData(nbt); + this.setAge(nbt.getInt("Age")); ++ this.ageLocked = nbt.getBoolean("AgeLocked"); // Paper + } + + @Nullable +@@ -169,6 +172,7 @@ public class Tadpole extends AbstractFish { + Bucketable.saveDefaultDataToBucketTag(this, stack); + CustomData.update(DataComponents.BUCKET_ENTITY_DATA, stack, (nbttagcompound) -> { + nbttagcompound.putInt("Age", this.getAge()); ++ nbttagcompound.putBoolean("AgeLocked", this.ageLocked); // Paper + }); + } + +@@ -179,6 +183,7 @@ public class Tadpole extends AbstractFish { + this.setAge(nbt.getInt("Age")); + } + ++ this.ageLocked = nbt.getBoolean("AgeLocked"); // Paper + } + + @Override +@@ -210,6 +215,7 @@ public class Tadpole extends AbstractFish { + } + + private void ageUp(int seconds) { ++ if (this.ageLocked) return; // Paper + this.setAge(this.age + seconds * 20); + } + +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 709237639ef0ec1cb623f270302a27b0072e8685..74151d69380e4adede40c7d7fc20834553706730 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 +@@ -779,6 +779,15 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + + } + ++ // Paper start - Horse API ++ public void setMouthOpen(boolean open) { ++ this.setFlag(FLAG_OPEN_MOUTH, open); ++ } ++ public boolean isMouthOpen() { ++ return this.getFlag(FLAG_OPEN_MOUTH); ++ } ++ // Paper end - Horse API ++ + @Override + public InteractionResult mobInteract(Player player, InteractionHand hand) { + if (!this.isVehicle() && !this.isBaby()) { +@@ -821,6 +830,11 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + this.setFlag(16, eatingGrass); + } + ++ // Paper start - Horse API ++ public void setForceStanding(boolean standing) { ++ this.setFlag(FLAG_STANDING, standing); ++ } ++ // Paper end - Horse API + public void setStanding(boolean angry) { + if (angry) { + this.setEating(false); +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 04842dd7b9beabcecbd492d0b98faaebeea1a5d9..d5808d0c190877554a4a8191f68e8b4a36f2ff46 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 +@@ -71,11 +71,12 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, Level world) { + super(type, world); + this.getNavigation().setRequiredPathLength(40.0F); ++ this.maxDomestication = 30; // Paper - Missing entity API; configure max temper instead of a hardcoded value + } + + public boolean isTraderLlama() { +@@ -294,7 +295,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, Level world) { + super(type, world); +@@ -591,7 +596,7 @@ public class WitherBoss extends Monster implements RangedAttackMob { + + @Override + public boolean canUsePortal(boolean allowVehicles) { +- return false; ++ return this.canPortal; // Paper + } + + @Override +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 0ddbebbe6eea00c379f2a250f7a44ba9313c1de1..4b798695af365dc97cbbbd09f370b8fc425f9ed6 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +@@ -428,6 +428,16 @@ public class EnderMan extends Monster implements NeutralMob { + this.entityData.set(EnderMan.DATA_STARED_AT, true); + } + ++ // Paper start ++ public void setCreepy(boolean creepy) { ++ this.entityData.set(EnderMan.DATA_CREEPY, creepy); ++ } ++ ++ public void setHasBeenStaredAt(boolean hasBeenStaredAt) { ++ this.entityData.set(EnderMan.DATA_STARED_AT, hasBeenStaredAt); ++ } ++ // Paper end ++ + @Override + public boolean requiresCustomPersistence() { + return super.requiresCustomPersistence() || this.getCarriedBlock() != null; +diff --git a/src/main/java/net/minecraft/world/entity/monster/Ghast.java b/src/main/java/net/minecraft/world/entity/monster/Ghast.java +index 71259b92a01a4feca270a250b1964f25f6da2d33..a8c8c03e972aa6352843cf4c3e4aebfb8f493125 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Ghast.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Ghast.java +@@ -66,6 +66,12 @@ public class Ghast extends FlyingMob implements Enemy { + return this.explosionPower; + } + ++ // Paper start ++ public void setExplosionPower(int explosionPower) { ++ this.explosionPower = explosionPower; ++ } ++ // Paper end ++ + @Override + protected boolean shouldDespawnInPeaceful() { + return true; +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 7f4c186a757e51ac788ec664a2c75dc7d7ce0eb3..a5d13b8bf7d0b6423ef428042e1134f5999cc24b 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -207,6 +207,12 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + } + + public void startConverting(@Nullable UUID uuid, int delay) { ++ // Paper start - missing entity behaviour api - converting without entity event ++ this.startConverting(uuid, delay, true); ++ } ++ ++ public void startConverting(@Nullable UUID uuid, int delay, boolean broadcastEntityEvent) { ++ // Paper end - missing entity behaviour api - converting without entity event + this.conversionStarter = uuid; + this.villagerConversionTime = delay; + this.getEntityData().set(ZombieVillager.DATA_CONVERTING_ID, true); +@@ -214,7 +220,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + this.removeEffect(MobEffects.WEAKNESS, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); + this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, delay, Math.min(this.level().getDifficulty().getId() - 1, 0)), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); + // CraftBukkit end +- this.level().broadcastEntityEvent(this, (byte) 16); ++ if (broadcastEntityEvent) this.level().broadcastEntityEvent(this, (byte) 16); // Paper - missing entity behaviour api - converting without entity event + } + + @Override +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 20a9dae93ee17bdef16b67a2db8e5e78b94d2c53..3888f13a49af26b0ece8813b607c20fc380cecd5 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java +@@ -114,6 +114,20 @@ public class ThrownTrident extends AbstractArrow { + return (Boolean) this.entityData.get(ThrownTrident.ID_FOIL); + } + ++ // Paper start ++ public void setFoil(boolean foil) { ++ this.entityData.set(ThrownTrident.ID_FOIL, foil); ++ } ++ ++ public int getLoyalty() { ++ return this.entityData.get(ThrownTrident.ID_LOYALTY); ++ } ++ ++ public void setLoyalty(byte loyalty) { ++ this.entityData.set(ThrownTrident.ID_LOYALTY, loyalty); ++ } ++ // Paper end ++ + @Nullable + @Override + protected EntityHitResult findHitEntity(Vec3 currentPosition, Vec3 nextPosition) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java +index 3952e52b94c1cc97e1d2d3885f59d7690efb74ad..9bcc0931510607b8fbd01233e2b3c346369b214d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java +@@ -114,4 +114,36 @@ public abstract class CraftAbstractHorse extends CraftAnimals implements Abstrac + public AbstractHorseInventory getInventory() { + return new CraftSaddledInventory(getHandle().inventory); + } ++ ++ // Paper start - Horse API ++ @Override ++ public boolean isEatingGrass() { ++ return this.getHandle().isEating(); ++ } ++ ++ @Override ++ public void setEatingGrass(boolean eating) { ++ this.getHandle().setEating(eating); ++ } ++ ++ @Override ++ public boolean isRearing() { ++ return this.getHandle().isStanding(); ++ } ++ ++ @Override ++ public void setRearing(boolean rearing) { ++ this.getHandle().setForceStanding(rearing); ++ } ++ ++ @Override ++ public boolean isEating() { ++ return this.getHandle().isMouthOpen(); ++ } ++ ++ @Override ++ public void setEating(boolean eating) { ++ this.getHandle().setMouthOpen(eating); ++ } ++ // Paper end - Horse API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java +index 17bffb45453f15328ca91794e26f6be1defef700..6591513bb62226b6f85fd2ef9f6ebe376f0f7362 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java +@@ -229,4 +229,17 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud + this.getHandle().setOwner(null); + } + } ++ ++ // Paper start - owner API ++ @Override ++ public java.util.UUID getOwnerUniqueId() { ++ return this.getHandle().ownerUUID; ++ } ++ ++ @Override ++ public void setOwnerUniqueId(final java.util.UUID ownerUuid) { ++ this.getHandle().setOwner(null); ++ this.getHandle().ownerUUID = ownerUuid; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java +index b0a3531476f5a05ae846b68d825eddc35ebddea9..1bb72f28085f3885bec068b586ec222111044884 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java +@@ -27,4 +27,25 @@ public class CraftBat extends CraftAmbient implements Bat { + public void setAwake(boolean state) { + this.getHandle().setResting(!state); + } ++ // Paper start ++ @Override ++ public org.bukkit.Location getTargetLocation() { ++ net.minecraft.core.BlockPos pos = this.getHandle().targetPosition; ++ if (pos == null) { ++ return null; ++ } ++ ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), pos); ++ } ++ ++ @Override ++ public void setTargetLocation(org.bukkit.Location location) { ++ net.minecraft.core.BlockPos pos = null; ++ if (location != null) { ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); ++ } ++ ++ this.getHandle().targetPosition = pos; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBee.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBee.java +index cfff1be6a4a4936a2dadb2590abc3d33c123d048..3dac93b0ab5d5acf5b33dc4b0efed60319eb657b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBee.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBee.java +@@ -86,4 +86,42 @@ public class CraftBee extends CraftAnimals implements Bee { + public void setCannotEnterHiveTicks(int ticks) { + this.getHandle().setStayOutOfHiveCountdown(ticks); + } ++ // Paper start ++ @Override ++ public void setRollingOverride(net.kyori.adventure.util.TriState rolling) { ++ this.getHandle().rollingOverride = rolling; ++ ++ this.getHandle().setRolling(this.getHandle().isRolling()); // Refresh rolling state ++ } ++ ++ @Override ++ public boolean isRolling() { ++ return this.getRollingOverride().toBooleanOrElse(this.getHandle().isRolling()); ++ } ++ ++ @Override ++ public net.kyori.adventure.util.TriState getRollingOverride() { ++ return this.getHandle().rollingOverride; ++ } ++ ++ @Override ++ public void setCropsGrownSincePollination(int crops) { ++ this.getHandle().numCropsGrownSincePollination = crops; ++ } ++ ++ @Override ++ public int getCropsGrownSincePollination() { ++ return this.getHandle().numCropsGrownSincePollination; ++ } ++ ++ @Override ++ public void setTicksSincePollination(int ticks) { ++ this.getHandle().ticksWithoutNectarSinceExitingHive = ticks; ++ } ++ ++ @Override ++ public int getTicksSincePollination() { ++ return this.getHandle().ticksWithoutNectarSinceExitingHive; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java +index 57664124968e6268ad6699c6bd932981cc2fe6ba..88e876da7df64b68a5b71fd1deab75b59c5a64e3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java +@@ -139,4 +139,26 @@ public class CraftCat extends CraftTameableAnimal implements Cat { + return this.getKey().hashCode(); + } + } ++ ++ // Paper start - More cat api ++ @Override ++ public void setLyingDown(boolean lyingDown) { ++ this.getHandle().setLying(lyingDown); ++ } ++ ++ @Override ++ public boolean isLyingDown() { ++ return this.getHandle().isLying(); ++ } ++ ++ @Override ++ public void setHeadUp(boolean headUp) { ++ this.getHandle().setRelaxStateOne(headUp); ++ } ++ ++ @Override ++ public boolean isHeadUp() { ++ return this.getHandle().isRelaxStateOne(); ++ } ++ // Paper end - More cat api + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java +index 64b75682a936e071353707f7615d6ff512fd617d..96f6e2fd9c6b20d34122abfe5c7fba732502d5a0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java +@@ -18,4 +18,26 @@ public class CraftChicken extends CraftAnimals implements Chicken { + public String toString() { + return "CraftChicken"; + } ++ ++ // Paper start ++ @Override ++ public boolean isChickenJockey() { ++ return this.getHandle().isChickenJockey(); ++ } ++ ++ @Override ++ public void setIsChickenJockey(boolean isChickenJockey) { ++ this.getHandle().setChickenJockey(isChickenJockey); ++ } ++ ++ @Override ++ public int getEggLayTime() { ++ return this.getHandle().eggTime; ++ } ++ ++ @Override ++ public void setEggLayTime(int eggLayTime) { ++ this.getHandle().eggTime = eggLayTime; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftCod.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftCod.java +index fa0bf7db880063427ba12df1df1c72240fff93e9..63e6b07e3b159c74d9ef17be20b5ab43d07f0f5f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftCod.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftCod.java +@@ -3,7 +3,7 @@ package org.bukkit.craftbukkit.entity; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.entity.Cod; + +-public class CraftCod extends CraftFish implements Cod { ++public class CraftCod extends io.papermc.paper.entity.PaperSchoolableFish implements Cod { // Paper - School Fish API + + public CraftCod(CraftServer server, net.minecraft.world.entity.animal.Cod entity) { + super(server, entity); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java +index 5bae70ad160d0d0912aa9ef054c5515812957289..83867b9c5497e6e793b21c482646cc419587e182 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java +@@ -18,4 +18,36 @@ public class CraftDolphin extends CraftAgeable implements Dolphin { + public String toString() { + return "CraftDolphin"; + } ++ ++ // Paper start - Missing Dolphin API ++ @Override ++ public int getMoistness() { ++ return this.getHandle().getMoistnessLevel(); ++ } ++ ++ @Override ++ public void setMoistness(int moistness) { ++ this.getHandle().setMoisntessLevel(moistness); ++ } ++ ++ @Override ++ public void setHasFish(boolean hasFish) { ++ this.getHandle().setGotFish(hasFish); ++ } ++ ++ @Override ++ public boolean hasFish() { ++ return this.getHandle().gotFish(); ++ } ++ ++ @Override ++ public org.bukkit.Location getTreasureLocation() { ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), this.getHandle().getTreasurePos()); ++ } ++ ++ @Override ++ public void setTreasureLocation(org.bukkit.Location location) { ++ this.getHandle().setTreasurePos(io.papermc.paper.util.MCUtil.toBlockPosition(location)); ++ } ++ // Paper end - Missing Dolphin API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragonPart.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragonPart.java +index cc4194ac9d7501b5d15655674dade14d59cb6733..33ae03b78b01c005a291a343b42507fb539e81a6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragonPart.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragonPart.java +@@ -51,6 +51,13 @@ public class CraftEnderDragonPart extends CraftComplexPart implements EnderDrago + this.getParent().setHealth(health); + } + ++ // Paper start - entity heal API ++ @Override ++ public void heal(final double amount, final org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason reason) { ++ this.getParent().heal(amount, reason); ++ } ++ // Paper end - entity heal API ++ + @Override + public double getAbsorptionAmount() { + return this.getParent().getAbsorptionAmount(); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java +index 21dc209e6f98b6306833b41e2763e746047d5a94..983b9d6ddb58eff297e96e5c8b28ec427efa267d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java +@@ -40,6 +40,28 @@ public class CraftEnderman extends CraftMonster implements Enderman { + this.getHandle().setCarriedBlock(blockData == null ? null : ((CraftBlockData) blockData).getState()); + } + ++ // Paper start ++ @Override ++ public boolean isScreaming() { ++ return this.getHandle().isCreepy(); ++ } ++ ++ @Override ++ public void setScreaming(boolean screaming) { ++ this.getHandle().setCreepy(screaming); ++ } ++ ++ @Override ++ public boolean hasBeenStaredAt() { ++ return this.getHandle().hasBeenStaredAt(); ++ } ++ ++ @Override ++ public void setHasBeenStaredAt(boolean hasBeenStaredAt) { ++ this.getHandle().setHasBeenStaredAt(hasBeenStaredAt); ++ } ++ // Paper end ++ + @Override + public EnderMan getHandle() { + return (EnderMan) this.entity; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java +index fc0f0e841dc974d080e1abb9bbafb5165801131f..d657fd2c507a5b215aeab0a5f3e9c2ee892a27c8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java +@@ -28,4 +28,15 @@ public class CraftEndermite extends CraftMonster implements Endermite { + public void setPlayerSpawned(boolean playerSpawned) { + // Nop + } ++ // Paper start ++ @Override ++ public void setLifetimeTicks(int ticks) { ++ this.getHandle().life = ticks; ++ } ++ ++ @Override ++ public int getLifetimeTicks() { ++ return this.getHandle().life; ++ } ++ // 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 78afac72265e3f586c0203951b8237832fb7c6fb..888a75423ac90ca85308eeb6d67bac5348bf31e0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1082,4 +1082,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return set; + } + // Paper end - tracked players API ++ ++ // Paper start - missing entity api ++ @Override ++ public boolean isInvisible() { // Paper - moved up from LivingEntity ++ return this.getHandle().isInvisible(); ++ } ++ ++ @Override ++ public void setInvisible(boolean invisible) { // Paper - moved up from LivingEntity ++ this.getHandle().persistentInvisibility = invisible; ++ this.getHandle().setSharedFlag(Entity.FLAG_INVISIBLE, invisible); ++ } ++ ++ @Override ++ public void setNoPhysics(boolean noPhysics) { ++ this.getHandle().noPhysics = noPhysics; ++ } ++ ++ @Override ++ public boolean hasNoPhysics() { ++ return this.getHandle().noPhysics; ++ } ++ // Paper end - missing entity api + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java +index 142f3e3257afebb2e831fd0970678123d99a1717..1b084d63bdbb24dad45d28eed1693eb6e26e24dc 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java +@@ -84,6 +84,18 @@ public class CraftFireball extends AbstractProjectile implements Fireball { + return new Vector(delta.x, delta.y, delta.z); + } + ++ // Paper start - Expose power on fireball projectiles ++ @Override ++ public void setPower(final Vector power) { ++ this.setAcceleration(power); ++ } ++ ++ @Override ++ public Vector getPower() { ++ return this.getAcceleration(); ++ } ++ // Paper end - Expose power on fireball projectiles ++ + @Override + public AbstractHurtingProjectile getHandle() { + return (AbstractHurtingProjectile) this.entity; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFox.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFox.java +index dd912be2933864236cd4fb35631d505972082d77..bb2b59ce9775a0d1dd9828885e57c14cf40d9f04 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFox.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFox.java +@@ -113,4 +113,41 @@ public class CraftFox extends CraftAnimals implements Fox { + public boolean isFaceplanted() { + return this.getHandle().isFaceplanted(); + } ++ ++ // Paper start - Add more fox behavior API ++ @Override ++ public void setInterested(boolean interested) { ++ this.getHandle().setIsInterested(interested); ++ } ++ ++ @Override ++ public boolean isInterested() { ++ return this.getHandle().isInterested(); ++ } ++ ++ @Override ++ public void setLeaping(boolean leaping) { ++ this.getHandle().setIsPouncing(leaping); ++ } ++ ++ @Override ++ public boolean isLeaping() { ++ return this.getHandle().isPouncing(); ++ } ++ ++ @Override ++ public void setDefending(boolean defending) { ++ this.getHandle().setDefending(defending); ++ } ++ ++ @Override ++ public boolean isDefending() { ++ return this.getHandle().isDefending(); ++ } ++ ++ @Override ++ public void setFaceplanted(boolean faceplanted) { ++ this.getHandle().setFaceplanted(faceplanted); ++ } ++ // Paper end - Add more fox behavior API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java +index 2cec61a1bb050c1ef81c5fc3d0afafe9ff29d459..97fa4e1e70203194bd939618b2fad92665af6d59 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java +@@ -28,4 +28,17 @@ public class CraftGhast extends CraftFlying implements Ghast, CraftEnemy { + public void setCharging(boolean flag) { + this.getHandle().setCharging(flag); + } ++ ++ // Paper start ++ @Override ++ public int getExplosionPower() { ++ return this.getHandle().getExplosionPower(); ++ } ++ ++ @Override ++ public void setExplosionPower(int explosionPower) { ++ com.google.common.base.Preconditions.checkArgument(explosionPower >= 0 && explosionPower <= 127, "The explosion power has to be between 0 and 127"); ++ this.getHandle().setExplosionPower(explosionPower); ++ } ++ // 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 a4a30f52f45bf91dc88d53f5d6a376ed739d09eb..6020c0c164595db4e2001edf0c1fbe99ed87682d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -128,6 +128,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + } + } + ++ // Paper start - entity heal API ++ @Override ++ public void heal(final double amount, final org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason reason) { ++ this.getHandle().heal((float) amount, reason); ++ } ++ // Paper end - entity heal API ++ + @Override + public double getAbsorptionAmount() { + return this.getHandle().getAbsorptionAmount(); +@@ -939,14 +946,29 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + + @Override + public boolean isInvisible() { +- return this.getHandle().isInvisible(); ++ return super.isInvisible(); // Paper - move invisibility up to Entity - diff on change + } + + @Override + public void setInvisible(boolean invisible) { +- this.getHandle().persistentInvisibility = invisible; +- this.getHandle().setSharedFlag(5, invisible); ++ super.setInvisible(invisible); // Paper - move invisibility up to Entity + } ++ // Paper start ++ @Override ++ public float getSidewaysMovement() { ++ return this.getHandle().xxa; ++ } ++ ++ @Override ++ public float getForwardsMovement() { ++ return this.getHandle().zza; ++ } ++ ++ @Override ++ public float getUpwardsMovement() { ++ return this.getHandle().yya; ++ } ++ // Paper end + + // Paper start + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java +index bf297388c75521266c93580a9caafe6bad70ab45..351f42842b780d053cd2e5bad9ae299449141b10 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java +@@ -58,4 +58,36 @@ public class CraftLlama extends CraftChestedHorse implements Llama, com.destroys + public String toString() { + return "CraftLlama"; + } ++ ++ // Paper start ++ @Override ++ public boolean inCaravan() { ++ return this.getHandle().inCaravan(); ++ } ++ ++ @Override ++ public void joinCaravan(@org.jetbrains.annotations.NotNull Llama llama) { ++ this.getHandle().joinCaravan(((CraftLlama) llama).getHandle()); ++ } ++ ++ @Override ++ public void leaveCaravan() { ++ this.getHandle().leaveCaravan(); ++ } ++ ++ @Override ++ public boolean hasCaravanTail() { ++ return this.getHandle().hasCaravanTail(); ++ } ++ ++ @Override ++ public Llama getCaravanHead() { ++ return this.getHandle().getCaravanHead() == null ? null : (Llama) this.getHandle().getCaravanHead().getBukkitEntity(); ++ } ++ ++ @Override ++ public Llama getCaravanTail() { ++ return this.getHandle().caravanTail == null ? null : (Llama) this.getHandle().caravanTail.getBukkitEntity(); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java +index 17f5684cba9d3ed22d9925d1951520cc4751dfe2..3a3563a1bdbc0d84d973b3a04b50b78b4bc3d379 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java +@@ -33,4 +33,20 @@ public final class CraftMinecartHopper extends CraftMinecartContainer implements + public void setEnabled(boolean enabled) { + ((MinecartHopper) this.getHandle()).setEnabled(enabled); + } ++ // Paper start ++ @Override ++ public net.minecraft.world.entity.vehicle.MinecartHopper getHandle() { ++ return (net.minecraft.world.entity.vehicle.MinecartHopper) super.getHandle(); ++ } ++ ++ @Override ++ public int getPickupCooldown() { ++ throw new UnsupportedOperationException("Hopper minecarts don't have cooldowns"); ++ } ++ ++ @Override ++ public void setPickupCooldown(int cooldown) { ++ throw new UnsupportedOperationException("Hopper minecarts don't have cooldowns"); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +index bd739428a7e5e35ebcdb70cd187379b3d222339b..7cf42f62d91c131b1cab576979f85c58c3cecb3b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +@@ -146,4 +146,16 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { + return getHandle().getMaxHeadXRot(); + } + // Paper end ++ ++ // Paper start ++ @Override ++ public boolean isAggressive() { ++ return this.getHandle().isAggressive(); ++ } ++ ++ @Override ++ public void setAggressive(boolean aggressive) { ++ this.getHandle().setAggressive(aggressive); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPanda.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPanda.java +index 5467e4a74b70ff57b49d9e6bc686c493178f8511..01d104d91de9e1319d27e39d3f474318c7809486 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPanda.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPanda.java +@@ -41,6 +41,38 @@ public class CraftPanda extends CraftAnimals implements Panda { + this.getHandle().setHiddenGene(CraftPanda.toNms(gene)); + } + ++ // Paper start - Panda API ++ @Override ++ public void setSneezeTicks(int ticks) { ++ this.getHandle().setSneezeCounter(ticks); ++ } ++ ++ @Override ++ public int getSneezeTicks() { ++ return this.getHandle().getSneezeCounter(); ++ } ++ ++ @Override ++ public void setEatingTicks(int ticks) { ++ this.getHandle().setEatCounter(ticks); ++ } ++ ++ @Override ++ public int getEatingTicks() { ++ return this.getHandle().getEatCounter(); ++ } ++ ++ @Override ++ public void setUnhappyTicks(int ticks) { ++ this.getHandle().setUnhappyCounter(ticks); ++ } ++ ++ @Override ++ public Gene getCombinedGene() { ++ return CraftPanda.fromNms(this.getHandle().getVariant()); ++ } ++ // Paper end - Panda API ++ + @Override + public boolean isRolling() { + return this.getHandle().isRolling(); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java +index 9304e201db1ec96d0916aa8ea781f3e4bc7991e6..83e77c6d287d8e239d2f55f3e9f19ef74946be7c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java +@@ -44,5 +44,17 @@ public class CraftPhantom extends CraftFlying implements Phantom, CraftEnemy { + public void setShouldBurnInDay(boolean shouldBurnInDay) { + getHandle().setShouldBurnInDay(shouldBurnInDay); + } ++ ++ @Override ++ public org.bukkit.Location getAnchorLocation() { ++ net.minecraft.core.BlockPos pos = this.getHandle().anchorPoint; ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), pos); ++ } ++ ++ @Override ++ public void setAnchorLocation(org.bukkit.Location location) { ++ com.google.common.base.Preconditions.checkArgument(location != null, "location cannot be null"); ++ this.getHandle().anchorPoint = io.papermc.paper.util.MCUtil.toBlockPosition(location); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java +index f5ecb8c1dc92e5a4b123effd2859123b17a586d3..5124a383b60b2c8de89fa992547d0c61db760c21 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java +@@ -84,4 +84,37 @@ public class CraftPiglin extends CraftPiglinAbstract implements Piglin, com.dest + public String toString() { + return "CraftPiglin"; + } ++ // Paper start ++ @Override ++ public void setChargingCrossbow(boolean chargingCrossbow) { ++ this.getHandle().setChargingCrossbow(chargingCrossbow); ++ } ++ ++ @Override ++ public boolean isChargingCrossbow() { ++ return this.getHandle().isChargingCrossbow(); ++ } ++ ++ @Override ++ public void setDancing(boolean dancing) { ++ if (dancing) { ++ this.getHandle().getBrain().setMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.DANCING, true); ++ this.getHandle().getBrain().setMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.CELEBRATE_LOCATION, this.getHandle().getOnPos()); ++ } else { ++ this.getHandle().getBrain().eraseMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.DANCING); ++ this.getHandle().getBrain().eraseMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.CELEBRATE_LOCATION); ++ } ++ } ++ ++ @Override ++ public void setDancing(long duration) { ++ this.getHandle().getBrain().setMemoryWithExpiry(net.minecraft.world.entity.ai.memory.MemoryModuleType.DANCING, true, duration); ++ this.getHandle().getBrain().setMemoryWithExpiry(net.minecraft.world.entity.ai.memory.MemoryModuleType.CELEBRATE_LOCATION, this.getHandle().getOnPos(), duration); ++ } ++ ++ @Override ++ public boolean isDancing() { ++ return this.getHandle().isDancing(); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPolarBear.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPolarBear.java +index c7aec6f28e5d3546235b30f6b1112440a76163c5..fe075cfdf3097d6cb768e71b8cc360abb8eaf367 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPolarBear.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPolarBear.java +@@ -17,4 +17,16 @@ public class CraftPolarBear extends CraftAnimals implements PolarBear { + public String toString() { + return "CraftPolarBear"; + } ++ ++ // Paper start ++ @Override ++ public boolean isStanding() { ++ return this.getHandle().isStanding(); ++ } ++ ++ @Override ++ public void setStanding(boolean standing) { ++ this.getHandle().setStanding(standing); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java +index 6b48b117a9cba12aae055c0ea981dfb5bc03a86e..519ef701a7d6534f7cb516f6296b95ee521f661d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java +@@ -29,4 +29,15 @@ public class CraftRabbit extends CraftAnimals implements Rabbit { + public void setRabbitType(Type type) { + this.getHandle().setVariant(net.minecraft.world.entity.animal.Rabbit.Variant.values()[type.ordinal()]); + } ++ // Paper start ++ @Override ++ public void setMoreCarrotTicks(int ticks) { ++ this.getHandle().moreCarrotTicks = ticks; ++ } ++ ++ @Override ++ public int getMoreCarrotTicks() { ++ return this.getHandle().moreCarrotTicks; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftRavager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftRavager.java +index cae59f77c704a5b9515dc4917ed5fdc89631ecfb..09796ce15658e3f7c223a265a547a51ee729ed40 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftRavager.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftRavager.java +@@ -18,4 +18,35 @@ public class CraftRavager extends CraftRaider implements Ravager { + public String toString() { + return "CraftRavager"; + } ++ // Paper start - Missing Entity Behavior ++ @Override ++ public int getAttackTicks() { ++ return this.getHandle().getAttackTick(); ++ } ++ ++ @Override ++ public void setAttackTicks(int ticks) { ++ this.getHandle().attackTick = ticks; ++ } ++ ++ @Override ++ public int getStunnedTicks() { ++ return this.getHandle().getStunnedTick(); ++ } ++ ++ @Override ++ public void setStunnedTicks(int ticks) { ++ this.getHandle().stunnedTick = ticks; ++ } ++ ++ @Override ++ public int getRoarTicks() { ++ return this.getHandle().getRoarTick(); ++ } ++ ++ @Override ++ public void setRoarTicks(int ticks) { ++ this.getHandle().roarTick = ticks; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSalmon.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSalmon.java +index 551c30cb0fb41dfe4a03663d34ecf9764566c215..7660cc21e936002ebb23510f0ec2b58d71e5157d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSalmon.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSalmon.java +@@ -4,7 +4,7 @@ import com.google.common.base.Preconditions; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.entity.Salmon; + +-public class CraftSalmon extends CraftFish implements Salmon { ++public class CraftSalmon extends io.papermc.paper.entity.PaperSchoolableFish implements Salmon { // Paper - Schooling Fish API + + public CraftSalmon(CraftServer server, net.minecraft.world.entity.animal.Salmon entity) { + super(server, entity); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java +index 36ab282e2c4060bdea4e57f3ab9dfef9f6cd622c..a61aec087fa7cec27a803668bdc1b9e6eb336755 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java +@@ -67,4 +67,17 @@ public class CraftTNTPrimed extends CraftEntity implements TNTPrimed { + this.getHandle().owner = null; + } + } ++ ++ // Paper start ++ @Override ++ public void setBlockData(org.bukkit.block.data.BlockData data) { ++ com.google.common.base.Preconditions.checkArgument(data != null, "The visual block data of this tnt cannot be null. To reset it just set to the TNT default block data"); ++ this.getHandle().setBlockState(((org.bukkit.craftbukkit.block.data.CraftBlockData) data).getState()); ++ } ++ ++ @Override ++ public org.bukkit.block.data.BlockData getBlockData() { ++ return org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(this.getHandle().getBlockState()); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java +index 451a9bfd9b9b6945e224f1bb05c7951ed934b4e3..d7c6a0bbc5671ea8f2488230c94df5146a1e98b9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java +@@ -28,4 +28,15 @@ public class CraftTadpole extends CraftFish implements org.bukkit.entity.Tadpole + public void setAge(int age) { + this.getHandle().age = age; + } ++ // Paper start ++ @Override ++ public void setAgeLock(boolean lock) { ++ this.getHandle().ageLocked = lock; ++ } ++ ++ @Override ++ public boolean getAgeLock() { ++ return this.getHandle().ageLocked; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java +index 33d6e8121755ad6cddacb4fc69e795f9831c27bd..e374b9f40eddca13b30855d25a2030f8df98138f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java +@@ -31,4 +31,27 @@ public class CraftTrident extends CraftAbstractArrow implements Trident { + public String toString() { + return "CraftTrident"; + } ++ ++ // Paper start ++ @Override ++ public boolean hasGlint() { ++ return this.getHandle().isFoil(); ++ } ++ ++ @Override ++ public void setGlint(boolean glint) { ++ this.getHandle().setFoil(glint); ++ } ++ ++ @Override ++ public int getLoyaltyLevel() { ++ return this.getHandle().getLoyalty(); ++ } ++ ++ @Override ++ public void setLoyaltyLevel(int loyaltyLevel) { ++ 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); ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTropicalFish.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTropicalFish.java +index e3bde6d1c0e03407af1382a61748470063bb2e18..9e53c30801c700719c78c0fd521fd615c94e02c8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTropicalFish.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTropicalFish.java +@@ -7,7 +7,7 @@ import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.entity.TropicalFish; + import org.bukkit.entity.TropicalFish.Pattern; + +-public class CraftTropicalFish extends CraftFish implements TropicalFish { ++public class CraftTropicalFish extends io.papermc.paper.entity.PaperSchoolableFish implements TropicalFish { // Paper - Schooling Fish API + + public CraftTropicalFish(CraftServer server, net.minecraft.world.entity.animal.TropicalFish entity) { + super(server, entity); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java +index 1cfbe9c476f4a254edf3edf4b70696bbaba78558..e9ec3455eabc473e104b5342a615a38c1ac25a4f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java +@@ -29,6 +29,26 @@ public class CraftVex extends CraftMonster implements Vex { + public void setSummoner(org.bukkit.entity.Mob summoner) { + getHandle().setOwner(summoner == null ? null : ((CraftMob) summoner).getHandle()); + } ++ ++ @Override ++ public boolean hasLimitedLifetime() { ++ return this.getHandle().hasLimitedLife; ++ } ++ ++ @Override ++ public void setLimitedLifetime(boolean hasLimitedLifetime) { ++ this.getHandle().hasLimitedLife = hasLimitedLifetime; ++ } ++ ++ @Override ++ public int getLimitedLifetimeTicks() { ++ return this.getHandle().limitedLifeTicks; ++ } ++ ++ @Override ++ public void setLimitedLifetimeTicks(int ticks) { ++ this.getHandle().limitedLifeTicks = ticks; ++ } + // Paper end + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java +index e2a0c11867abee6add8775259c54f2052de7b1ad..3aa23d9f22d5cd22231293fd7d1ca4cb79eb7cb3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java +@@ -60,13 +60,20 @@ public class CraftVillagerZombie extends CraftZombie implements ZombieVillager { + + @Override + public void setConversionTime(int time) { ++ // Paper start - missing entity behaviour api - converting without entity event ++ this.setConversionTime(time, true); ++ } ++ ++ @Override ++ public void setConversionTime(int time, boolean broadcastEntityEvent) { ++ // Paper end - missing entity behaviour api - converting without entity event + if (time < 0) { + this.getHandle().villagerConversionTime = -1; + this.getHandle().getEntityData().set(net.minecraft.world.entity.monster.ZombieVillager.DATA_CONVERTING_ID, false); + this.getHandle().conversionStarter = null; + this.getHandle().removeEffect(MobEffects.DAMAGE_BOOST, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); + } else { +- this.getHandle().startConverting(null, time); ++ this.getHandle().startConverting(null, time, broadcastEntityEvent); // Paper - missing entity behaviour api - converting without entity event + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java +index 0e597394a3dd08f022614fc9777302fea581eb55..3cceefa0d6278924a19641a49bdf16bcdacb2233 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java +@@ -49,5 +49,25 @@ public class CraftWanderingTrader extends CraftAbstractVillager implements Wande + public boolean canDrinkMilk() { + return getHandle().canDrinkMilk; + } ++ ++ @Override ++ public org.bukkit.Location getWanderingTowards() { ++ net.minecraft.core.BlockPos pos = this.getHandle().getWanderTarget(); ++ if (pos == null) { ++ return null; ++ } ++ ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), pos); ++ } ++ ++ @Override ++ public void setWanderingTowards(org.bukkit.Location location) { ++ net.minecraft.core.BlockPos pos = null; ++ if (location != null) { ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); ++ } ++ ++ this.getHandle().setWanderTarget(pos); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWarden.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWarden.java +index 794e4fe0a3fbd967f665b2707865c15491370c76..c284eb96a1e330078076cbe61f0f6e2ff4ed89bd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWarden.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWarden.java +@@ -37,6 +37,13 @@ public class CraftWarden extends CraftMonster implements org.bukkit.entity.Warde + return this.getHandle().getAngerManagement().getActiveAnger(((CraftEntity) entity).getHandle()); + } + ++ // Paper start ++ @Override ++ public int getHighestAnger() { ++ return this.getHandle().getAngerManagement().getActiveAnger(null); ++ } ++ // Paper end ++ + @Override + public void increaseAnger(Entity entity, int increase) { + Preconditions.checkArgument(entity != null, "Entity cannot be null"); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java +index 1113533d281ed159bb735040fb1f913482debf3a..7881c6253c1d652c0c0d54a9a8accdf0a1ff0f3e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java +@@ -67,4 +67,36 @@ public class CraftWither extends CraftMonster implements Wither, com.destroystok + + this.getHandle().setInvulnerableTicks(ticks); + } ++ ++ // Paper start ++ @Override ++ public boolean isCharged() { ++ return getHandle().isPowered(); ++ } ++ ++ @Override ++ public int getInvulnerableTicks() { ++ return getHandle().getInvulnerableTicks(); ++ } ++ ++ @Override ++ public void setInvulnerableTicks(int ticks) { ++ getHandle().setInvulnerableTicks(ticks); ++ } ++ ++ @Override ++ public boolean canTravelThroughPortals() { ++ return getHandle().canUsePortal(false); ++ } ++ ++ @Override ++ public void setCanTravelThroughPortals(boolean value) { ++ getHandle().setCanTravelThroughPortals(value); ++ } ++ ++ @Override ++ public void enterInvulnerabilityPhase() { ++ this.getHandle().makeInvulnerable(); ++ } ++ // Paper end + } diff --git a/patches/server/0550-Fix-return-value-of-Block-applyBoneMeal-always-being.patch b/patches/server/0550-Fix-return-value-of-Block-applyBoneMeal-always-being.patch new file mode 100644 index 0000000000..40cc161932 --- /dev/null +++ b/patches/server/0550-Fix-return-value-of-Block-applyBoneMeal-always-being.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Mon, 28 Jun 2021 18:16:52 -0700 +Subject: [PATCH] Fix return value of Block#applyBoneMeal always being false + + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 54fb380a6896731a18c0100722d12099e590cbc9..9c8aac69f01db647e20d49d272ccc107a7edceaf 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -558,7 +558,7 @@ public class CraftBlock implements Block { + } + } + +- return result == InteractionResult.SUCCESS && (event == null || !event.isCancelled()); ++ return result == InteractionResult.CONSUME && (event == null || !event.isCancelled()); // Paper - CONSUME is returned on success server-side (see BoneMealItem.applyBoneMeal and InteractionResult.sidedSuccess(boolean)) + } + + @Override diff --git a/patches/server/0550-Missing-Entity-API.patch b/patches/server/0550-Missing-Entity-API.patch deleted file mode 100644 index c9324ba0e3..0000000000 --- a/patches/server/0550-Missing-Entity-API.patch +++ /dev/null @@ -1,1402 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Mon, 21 Jun 2021 23:56:07 -0400 -Subject: [PATCH] Missing Entity API - -== AT == -public net.minecraft.world.entity.animal.Fox isDefending()Z -public net.minecraft.world.entity.animal.Fox setDefending(Z)V -public net.minecraft.world.entity.animal.Fox setFaceplanted(Z)V -public net.minecraft.world.entity.animal.Panda getEatCounter()I -public net.minecraft.world.entity.animal.Panda setEatCounter(I)V -public net.minecraft.world.entity.animal.Bee isRolling()Z -public net.minecraft.world.entity.animal.Bee setRolling(Z)V -public net.minecraft.world.entity.animal.Bee numCropsGrownSincePollination -public net.minecraft.world.entity.animal.Bee ticksWithoutNectarSinceExitingHive -public net.minecraft.world.entity.monster.piglin.Piglin isChargingCrossbow()Z -public net.minecraft.world.entity.ambient.Bat targetPosition -public net.minecraft.world.entity.monster.Ravager attackTick -public net.minecraft.world.entity.monster.Ravager stunnedTick -public net.minecraft.world.entity.monster.Ravager roarTick -public net.minecraft.world.entity.vehicle.MinecartTNT explode(D)V -public net.minecraft.world.entity.vehicle.MinecartTNT fuse -public net.minecraft.world.entity.monster.Endermite life -public net.minecraft.world.entity.projectile.AbstractArrow soundEvent -public net.minecraft.world.entity.monster.Phantom anchorPoint -public net.minecraft.world.entity.npc.WanderingTrader getWanderTarget()Lnet/minecraft/core/BlockPos; -public net.minecraft.world.entity.animal.AbstractSchoolingFish leader -public net.minecraft.world.entity.animal.AbstractSchoolingFish schoolSize -public net.minecraft.world.entity.animal.Rabbit moreCarrotTicks -public net.minecraft.world.entity.AreaEffectCloud ownerUUID -public net.minecraft.world.entity.animal.MushroomCow stewEffects -public net.minecraft.world.entity.Entity FLAG_INVISIBLE -public net.minecraft.world.entity.animal.Cat setRelaxStateOne(Z)V -public net.minecraft.world.entity.animal.Cat isRelaxStateOne()Z - -Co-authored-by: Nassim Jahnke -Co-authored-by: Jake Potrebic -Co-authored-by: William Blake Galbreath -Co-authored-by: SoSeDiK -Co-authored-by: booky10 -Co-authored-by: Amin -Co-authored-by: TrollyLoki -Co-authored-by: FireInstall -Co-authored-by: maxcom1 <46265094+maxcom1@users.noreply.github.com> -Co-authored-by: TotalledZebra - -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -index 36621b42f0dbca9d82a2ca284f30fd9eceab166e..d5d617d72c1d160564e3e53d3c6bdffe3d868145 100644 ---- a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -@@ -164,7 +164,7 @@ public class MobGoalHelper { - bukkitMap.put(net.minecraft.world.entity.monster.Endermite.class, Endermite.class); - bukkitMap.put(net.minecraft.world.entity.monster.Evoker.class, Evoker.class); - bukkitMap.put(AbstractFish.class, Fish.class); -- bukkitMap.put(AbstractSchoolingFish.class, Fish.class); // close enough -+ bukkitMap.put(AbstractSchoolingFish.class, io.papermc.paper.entity.SchoolableFish.class); - bukkitMap.put(FlyingMob.class, Flying.class); - bukkitMap.put(net.minecraft.world.entity.animal.Fox.class, Fox.class); - bukkitMap.put(net.minecraft.world.entity.monster.Ghast.class, Ghast.class); -diff --git a/src/main/java/io/papermc/paper/entity/PaperSchoolableFish.java b/src/main/java/io/papermc/paper/entity/PaperSchoolableFish.java -new file mode 100644 -index 0000000000000000000000000000000000000000..41bf71d116ffc5431586ce54abba7f8def6c1dcf ---- /dev/null -+++ b/src/main/java/io/papermc/paper/entity/PaperSchoolableFish.java -@@ -0,0 +1,52 @@ -+package io.papermc.paper.entity; -+ -+import net.minecraft.world.entity.animal.AbstractSchoolingFish; -+import org.bukkit.craftbukkit.CraftServer; -+import org.bukkit.craftbukkit.entity.CraftFish; -+import org.jetbrains.annotations.NotNull; -+ -+public class PaperSchoolableFish extends CraftFish implements SchoolableFish { -+ -+ public PaperSchoolableFish(CraftServer server, AbstractSchoolingFish entity) { -+ super(server, entity); -+ } -+ -+ @Override -+ public AbstractSchoolingFish getHandle() { -+ return (AbstractSchoolingFish) super.getHandle(); -+ } -+ -+ @Override -+ public void startFollowing(@NotNull SchoolableFish fish) { -+ if (this.getHandle().isFollower()) { // If following a fish already, properly remove the old one -+ this.stopFollowing(); -+ } -+ -+ this.getHandle().startFollowing(((PaperSchoolableFish) fish).getHandle()); -+ } -+ -+ @Override -+ public void stopFollowing() { -+ this.getHandle().stopFollowing(); -+ } -+ -+ @Override -+ public int getSchoolSize() { -+ return this.getHandle().schoolSize; -+ } -+ -+ @Override -+ public int getMaxSchoolSize() { -+ return this.getHandle().getMaxSchoolSize(); -+ } -+ -+ @Override -+ public SchoolableFish getSchoolLeader() { -+ AbstractSchoolingFish leader = this.getHandle().leader; -+ if (leader == null) { -+ return null; -+ } -+ -+ return (SchoolableFish) leader.getBukkitEntity(); -+ } -+} -diff --git a/src/main/java/net/minecraft/world/entity/animal/AbstractSchoolingFish.java b/src/main/java/net/minecraft/world/entity/animal/AbstractSchoolingFish.java -index 30095df7b64cfda4931dbfa22549ff5abefd53e0..c8ae49f58c254119c0e64a4e1501ebc5a70f9a46 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/AbstractSchoolingFish.java -+++ b/src/main/java/net/minecraft/world/entity/animal/AbstractSchoolingFish.java -@@ -51,6 +51,7 @@ public abstract class AbstractSchoolingFish extends AbstractFish { - } - - public void stopFollowing() { -+ if (this.leader == null) return; // Avoid NPE, plugins can now set the leader and certain fish goals might cause this method to be called - this.leader.removeFollower(); - this.leader = null; - } -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 a48a29b5b1963db679b053f3530f64d2b9560290..a5eab5cdb761e3e9d37ea66287f26a2c3345182d 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -565,11 +565,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - this.setFlag(4, hasStung); - } - -+ public net.kyori.adventure.util.TriState rollingOverride = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Rolling override - public boolean isRolling() { - return this.getFlag(2); - } - - public void setRolling(boolean nearTarget) { -+ nearTarget = rollingOverride.toBooleanOrElse(nearTarget); // Paper - Rolling override - this.setFlag(2, nearTarget); - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -index b9d7aa4aa0fc3472a2a0700e526778daf62bdc6f..48ac8c3f6e00c3c2dc67b6c994be7c0ac6dfcf81 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -@@ -50,6 +50,7 @@ public class Tadpole extends AbstractFish { - public int age; - protected static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.HURT_BY, SensorType.FROG_TEMPTATIONS); - protected static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.LOOK_TARGET, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.NEAREST_VISIBLE_ADULT, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.BREED_TARGET, MemoryModuleType.IS_PANICKING); -+ public boolean ageLocked; // Paper - - public Tadpole(EntityType type, Level world) { - super(type, world); -@@ -102,7 +103,7 @@ public class Tadpole extends AbstractFish { - @Override - public void aiStep() { - super.aiStep(); -- if (!this.level().isClientSide) { -+ if (!this.level().isClientSide && !this.ageLocked) { // Paper - this.setAge(this.age + 1); - } - -@@ -112,12 +113,14 @@ public class Tadpole extends AbstractFish { - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); - nbt.putInt("Age", this.age); -+ nbt.putBoolean("AgeLocked", this.ageLocked); // Paper - } - - @Override - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); - this.setAge(nbt.getInt("Age")); -+ this.ageLocked = nbt.getBoolean("AgeLocked"); // Paper - } - - @Nullable -@@ -169,6 +172,7 @@ public class Tadpole extends AbstractFish { - Bucketable.saveDefaultDataToBucketTag(this, stack); - CustomData.update(DataComponents.BUCKET_ENTITY_DATA, stack, (nbttagcompound) -> { - nbttagcompound.putInt("Age", this.getAge()); -+ nbttagcompound.putBoolean("AgeLocked", this.ageLocked); // Paper - }); - } - -@@ -179,6 +183,7 @@ public class Tadpole extends AbstractFish { - this.setAge(nbt.getInt("Age")); - } - -+ this.ageLocked = nbt.getBoolean("AgeLocked"); // Paper - } - - @Override -@@ -210,6 +215,7 @@ public class Tadpole extends AbstractFish { - } - - private void ageUp(int seconds) { -+ if (this.ageLocked) return; // Paper - this.setAge(this.age + seconds * 20); - } - -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 709237639ef0ec1cb623f270302a27b0072e8685..74151d69380e4adede40c7d7fc20834553706730 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 -@@ -779,6 +779,15 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - - } - -+ // Paper start - Horse API -+ public void setMouthOpen(boolean open) { -+ this.setFlag(FLAG_OPEN_MOUTH, open); -+ } -+ public boolean isMouthOpen() { -+ return this.getFlag(FLAG_OPEN_MOUTH); -+ } -+ // Paper end - Horse API -+ - @Override - public InteractionResult mobInteract(Player player, InteractionHand hand) { - if (!this.isVehicle() && !this.isBaby()) { -@@ -821,6 +830,11 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - this.setFlag(16, eatingGrass); - } - -+ // Paper start - Horse API -+ public void setForceStanding(boolean standing) { -+ this.setFlag(FLAG_STANDING, standing); -+ } -+ // Paper end - Horse API - public void setStanding(boolean angry) { - if (angry) { - this.setEating(false); -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 04842dd7b9beabcecbd492d0b98faaebeea1a5d9..d5808d0c190877554a4a8191f68e8b4a36f2ff46 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 -@@ -71,11 +71,12 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, Level world) { - super(type, world); - this.getNavigation().setRequiredPathLength(40.0F); -+ this.maxDomestication = 30; // Paper - Missing entity API; configure max temper instead of a hardcoded value - } - - public boolean isTraderLlama() { -@@ -294,7 +295,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, Level world) { - super(type, world); -@@ -591,7 +596,7 @@ public class WitherBoss extends Monster implements RangedAttackMob { - - @Override - public boolean canUsePortal(boolean allowVehicles) { -- return false; -+ return this.canPortal; // Paper - } - - @Override -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 0ddbebbe6eea00c379f2a250f7a44ba9313c1de1..4b798695af365dc97cbbbd09f370b8fc425f9ed6 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -428,6 +428,16 @@ public class EnderMan extends Monster implements NeutralMob { - this.entityData.set(EnderMan.DATA_STARED_AT, true); - } - -+ // Paper start -+ public void setCreepy(boolean creepy) { -+ this.entityData.set(EnderMan.DATA_CREEPY, creepy); -+ } -+ -+ public void setHasBeenStaredAt(boolean hasBeenStaredAt) { -+ this.entityData.set(EnderMan.DATA_STARED_AT, hasBeenStaredAt); -+ } -+ // Paper end -+ - @Override - public boolean requiresCustomPersistence() { - return super.requiresCustomPersistence() || this.getCarriedBlock() != null; -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ghast.java b/src/main/java/net/minecraft/world/entity/monster/Ghast.java -index 71259b92a01a4feca270a250b1964f25f6da2d33..a8c8c03e972aa6352843cf4c3e4aebfb8f493125 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ghast.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ghast.java -@@ -66,6 +66,12 @@ public class Ghast extends FlyingMob implements Enemy { - return this.explosionPower; - } - -+ // Paper start -+ public void setExplosionPower(int explosionPower) { -+ this.explosionPower = explosionPower; -+ } -+ // Paper end -+ - @Override - protected boolean shouldDespawnInPeaceful() { - return true; -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 7f4c186a757e51ac788ec664a2c75dc7d7ce0eb3..a5d13b8bf7d0b6423ef428042e1134f5999cc24b 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -207,6 +207,12 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - } - - public void startConverting(@Nullable UUID uuid, int delay) { -+ // Paper start - missing entity behaviour api - converting without entity event -+ this.startConverting(uuid, delay, true); -+ } -+ -+ public void startConverting(@Nullable UUID uuid, int delay, boolean broadcastEntityEvent) { -+ // Paper end - missing entity behaviour api - converting without entity event - this.conversionStarter = uuid; - this.villagerConversionTime = delay; - this.getEntityData().set(ZombieVillager.DATA_CONVERTING_ID, true); -@@ -214,7 +220,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - this.removeEffect(MobEffects.WEAKNESS, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); - this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, delay, Math.min(this.level().getDifficulty().getId() - 1, 0)), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); - // CraftBukkit end -- this.level().broadcastEntityEvent(this, (byte) 16); -+ if (broadcastEntityEvent) this.level().broadcastEntityEvent(this, (byte) 16); // Paper - missing entity behaviour api - converting without entity event - } - - @Override -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 20a9dae93ee17bdef16b67a2db8e5e78b94d2c53..3888f13a49af26b0ece8813b607c20fc380cecd5 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -@@ -114,6 +114,20 @@ public class ThrownTrident extends AbstractArrow { - return (Boolean) this.entityData.get(ThrownTrident.ID_FOIL); - } - -+ // Paper start -+ public void setFoil(boolean foil) { -+ this.entityData.set(ThrownTrident.ID_FOIL, foil); -+ } -+ -+ public int getLoyalty() { -+ return this.entityData.get(ThrownTrident.ID_LOYALTY); -+ } -+ -+ public void setLoyalty(byte loyalty) { -+ this.entityData.set(ThrownTrident.ID_LOYALTY, loyalty); -+ } -+ // Paper end -+ - @Nullable - @Override - protected EntityHitResult findHitEntity(Vec3 currentPosition, Vec3 nextPosition) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java -index 3952e52b94c1cc97e1d2d3885f59d7690efb74ad..9bcc0931510607b8fbd01233e2b3c346369b214d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java -@@ -114,4 +114,36 @@ public abstract class CraftAbstractHorse extends CraftAnimals implements Abstrac - public AbstractHorseInventory getInventory() { - return new CraftSaddledInventory(getHandle().inventory); - } -+ -+ // Paper start - Horse API -+ @Override -+ public boolean isEatingGrass() { -+ return this.getHandle().isEating(); -+ } -+ -+ @Override -+ public void setEatingGrass(boolean eating) { -+ this.getHandle().setEating(eating); -+ } -+ -+ @Override -+ public boolean isRearing() { -+ return this.getHandle().isStanding(); -+ } -+ -+ @Override -+ public void setRearing(boolean rearing) { -+ this.getHandle().setForceStanding(rearing); -+ } -+ -+ @Override -+ public boolean isEating() { -+ return this.getHandle().isMouthOpen(); -+ } -+ -+ @Override -+ public void setEating(boolean eating) { -+ this.getHandle().setMouthOpen(eating); -+ } -+ // Paper end - Horse API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java -index 17bffb45453f15328ca91794e26f6be1defef700..6591513bb62226b6f85fd2ef9f6ebe376f0f7362 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java -@@ -229,4 +229,17 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud - this.getHandle().setOwner(null); - } - } -+ -+ // Paper start - owner API -+ @Override -+ public java.util.UUID getOwnerUniqueId() { -+ return this.getHandle().ownerUUID; -+ } -+ -+ @Override -+ public void setOwnerUniqueId(final java.util.UUID ownerUuid) { -+ this.getHandle().setOwner(null); -+ this.getHandle().ownerUUID = ownerUuid; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java -index b0a3531476f5a05ae846b68d825eddc35ebddea9..1bb72f28085f3885bec068b586ec222111044884 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java -@@ -27,4 +27,25 @@ public class CraftBat extends CraftAmbient implements Bat { - public void setAwake(boolean state) { - this.getHandle().setResting(!state); - } -+ // Paper start -+ @Override -+ public org.bukkit.Location getTargetLocation() { -+ net.minecraft.core.BlockPos pos = this.getHandle().targetPosition; -+ if (pos == null) { -+ return null; -+ } -+ -+ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), pos); -+ } -+ -+ @Override -+ public void setTargetLocation(org.bukkit.Location location) { -+ net.minecraft.core.BlockPos pos = null; -+ if (location != null) { -+ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); -+ } -+ -+ this.getHandle().targetPosition = pos; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBee.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBee.java -index cfff1be6a4a4936a2dadb2590abc3d33c123d048..3dac93b0ab5d5acf5b33dc4b0efed60319eb657b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBee.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBee.java -@@ -86,4 +86,42 @@ public class CraftBee extends CraftAnimals implements Bee { - public void setCannotEnterHiveTicks(int ticks) { - this.getHandle().setStayOutOfHiveCountdown(ticks); - } -+ // Paper start -+ @Override -+ public void setRollingOverride(net.kyori.adventure.util.TriState rolling) { -+ this.getHandle().rollingOverride = rolling; -+ -+ this.getHandle().setRolling(this.getHandle().isRolling()); // Refresh rolling state -+ } -+ -+ @Override -+ public boolean isRolling() { -+ return this.getRollingOverride().toBooleanOrElse(this.getHandle().isRolling()); -+ } -+ -+ @Override -+ public net.kyori.adventure.util.TriState getRollingOverride() { -+ return this.getHandle().rollingOverride; -+ } -+ -+ @Override -+ public void setCropsGrownSincePollination(int crops) { -+ this.getHandle().numCropsGrownSincePollination = crops; -+ } -+ -+ @Override -+ public int getCropsGrownSincePollination() { -+ return this.getHandle().numCropsGrownSincePollination; -+ } -+ -+ @Override -+ public void setTicksSincePollination(int ticks) { -+ this.getHandle().ticksWithoutNectarSinceExitingHive = ticks; -+ } -+ -+ @Override -+ public int getTicksSincePollination() { -+ return this.getHandle().ticksWithoutNectarSinceExitingHive; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java -index 57664124968e6268ad6699c6bd932981cc2fe6ba..88e876da7df64b68a5b71fd1deab75b59c5a64e3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java -@@ -139,4 +139,26 @@ public class CraftCat extends CraftTameableAnimal implements Cat { - return this.getKey().hashCode(); - } - } -+ -+ // Paper start - More cat api -+ @Override -+ public void setLyingDown(boolean lyingDown) { -+ this.getHandle().setLying(lyingDown); -+ } -+ -+ @Override -+ public boolean isLyingDown() { -+ return this.getHandle().isLying(); -+ } -+ -+ @Override -+ public void setHeadUp(boolean headUp) { -+ this.getHandle().setRelaxStateOne(headUp); -+ } -+ -+ @Override -+ public boolean isHeadUp() { -+ return this.getHandle().isRelaxStateOne(); -+ } -+ // Paper end - More cat api - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java -index 64b75682a936e071353707f7615d6ff512fd617d..96f6e2fd9c6b20d34122abfe5c7fba732502d5a0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java -@@ -18,4 +18,26 @@ public class CraftChicken extends CraftAnimals implements Chicken { - public String toString() { - return "CraftChicken"; - } -+ -+ // Paper start -+ @Override -+ public boolean isChickenJockey() { -+ return this.getHandle().isChickenJockey(); -+ } -+ -+ @Override -+ public void setIsChickenJockey(boolean isChickenJockey) { -+ this.getHandle().setChickenJockey(isChickenJockey); -+ } -+ -+ @Override -+ public int getEggLayTime() { -+ return this.getHandle().eggTime; -+ } -+ -+ @Override -+ public void setEggLayTime(int eggLayTime) { -+ this.getHandle().eggTime = eggLayTime; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftCod.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftCod.java -index fa0bf7db880063427ba12df1df1c72240fff93e9..63e6b07e3b159c74d9ef17be20b5ab43d07f0f5f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftCod.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftCod.java -@@ -3,7 +3,7 @@ package org.bukkit.craftbukkit.entity; - import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.entity.Cod; - --public class CraftCod extends CraftFish implements Cod { -+public class CraftCod extends io.papermc.paper.entity.PaperSchoolableFish implements Cod { // Paper - School Fish API - - public CraftCod(CraftServer server, net.minecraft.world.entity.animal.Cod entity) { - super(server, entity); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java -index 5bae70ad160d0d0912aa9ef054c5515812957289..83867b9c5497e6e793b21c482646cc419587e182 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java -@@ -18,4 +18,36 @@ public class CraftDolphin extends CraftAgeable implements Dolphin { - public String toString() { - return "CraftDolphin"; - } -+ -+ // Paper start - Missing Dolphin API -+ @Override -+ public int getMoistness() { -+ return this.getHandle().getMoistnessLevel(); -+ } -+ -+ @Override -+ public void setMoistness(int moistness) { -+ this.getHandle().setMoisntessLevel(moistness); -+ } -+ -+ @Override -+ public void setHasFish(boolean hasFish) { -+ this.getHandle().setGotFish(hasFish); -+ } -+ -+ @Override -+ public boolean hasFish() { -+ return this.getHandle().gotFish(); -+ } -+ -+ @Override -+ public org.bukkit.Location getTreasureLocation() { -+ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), this.getHandle().getTreasurePos()); -+ } -+ -+ @Override -+ public void setTreasureLocation(org.bukkit.Location location) { -+ this.getHandle().setTreasurePos(io.papermc.paper.util.MCUtil.toBlockPosition(location)); -+ } -+ // Paper end - Missing Dolphin API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragonPart.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragonPart.java -index cc4194ac9d7501b5d15655674dade14d59cb6733..33ae03b78b01c005a291a343b42507fb539e81a6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragonPart.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragonPart.java -@@ -51,6 +51,13 @@ public class CraftEnderDragonPart extends CraftComplexPart implements EnderDrago - this.getParent().setHealth(health); - } - -+ // Paper start - entity heal API -+ @Override -+ public void heal(final double amount, final org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason reason) { -+ this.getParent().heal(amount, reason); -+ } -+ // Paper end - entity heal API -+ - @Override - public double getAbsorptionAmount() { - return this.getParent().getAbsorptionAmount(); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java -index 21dc209e6f98b6306833b41e2763e746047d5a94..983b9d6ddb58eff297e96e5c8b28ec427efa267d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java -@@ -40,6 +40,28 @@ public class CraftEnderman extends CraftMonster implements Enderman { - this.getHandle().setCarriedBlock(blockData == null ? null : ((CraftBlockData) blockData).getState()); - } - -+ // Paper start -+ @Override -+ public boolean isScreaming() { -+ return this.getHandle().isCreepy(); -+ } -+ -+ @Override -+ public void setScreaming(boolean screaming) { -+ this.getHandle().setCreepy(screaming); -+ } -+ -+ @Override -+ public boolean hasBeenStaredAt() { -+ return this.getHandle().hasBeenStaredAt(); -+ } -+ -+ @Override -+ public void setHasBeenStaredAt(boolean hasBeenStaredAt) { -+ this.getHandle().setHasBeenStaredAt(hasBeenStaredAt); -+ } -+ // Paper end -+ - @Override - public EnderMan getHandle() { - return (EnderMan) this.entity; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java -index fc0f0e841dc974d080e1abb9bbafb5165801131f..d657fd2c507a5b215aeab0a5f3e9c2ee892a27c8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java -@@ -28,4 +28,15 @@ public class CraftEndermite extends CraftMonster implements Endermite { - public void setPlayerSpawned(boolean playerSpawned) { - // Nop - } -+ // Paper start -+ @Override -+ public void setLifetimeTicks(int ticks) { -+ this.getHandle().life = ticks; -+ } -+ -+ @Override -+ public int getLifetimeTicks() { -+ return this.getHandle().life; -+ } -+ // 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 78afac72265e3f586c0203951b8237832fb7c6fb..888a75423ac90ca85308eeb6d67bac5348bf31e0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1082,4 +1082,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return set; - } - // Paper end - tracked players API -+ -+ // Paper start - missing entity api -+ @Override -+ public boolean isInvisible() { // Paper - moved up from LivingEntity -+ return this.getHandle().isInvisible(); -+ } -+ -+ @Override -+ public void setInvisible(boolean invisible) { // Paper - moved up from LivingEntity -+ this.getHandle().persistentInvisibility = invisible; -+ this.getHandle().setSharedFlag(Entity.FLAG_INVISIBLE, invisible); -+ } -+ -+ @Override -+ public void setNoPhysics(boolean noPhysics) { -+ this.getHandle().noPhysics = noPhysics; -+ } -+ -+ @Override -+ public boolean hasNoPhysics() { -+ return this.getHandle().noPhysics; -+ } -+ // Paper end - missing entity api - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java -index 142f3e3257afebb2e831fd0970678123d99a1717..1b084d63bdbb24dad45d28eed1693eb6e26e24dc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java -@@ -84,6 +84,18 @@ public class CraftFireball extends AbstractProjectile implements Fireball { - return new Vector(delta.x, delta.y, delta.z); - } - -+ // Paper start - Expose power on fireball projectiles -+ @Override -+ public void setPower(final Vector power) { -+ this.setAcceleration(power); -+ } -+ -+ @Override -+ public Vector getPower() { -+ return this.getAcceleration(); -+ } -+ // Paper end - Expose power on fireball projectiles -+ - @Override - public AbstractHurtingProjectile getHandle() { - return (AbstractHurtingProjectile) this.entity; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFox.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFox.java -index dd912be2933864236cd4fb35631d505972082d77..bb2b59ce9775a0d1dd9828885e57c14cf40d9f04 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFox.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFox.java -@@ -113,4 +113,41 @@ public class CraftFox extends CraftAnimals implements Fox { - public boolean isFaceplanted() { - return this.getHandle().isFaceplanted(); - } -+ -+ // Paper start - Add more fox behavior API -+ @Override -+ public void setInterested(boolean interested) { -+ this.getHandle().setIsInterested(interested); -+ } -+ -+ @Override -+ public boolean isInterested() { -+ return this.getHandle().isInterested(); -+ } -+ -+ @Override -+ public void setLeaping(boolean leaping) { -+ this.getHandle().setIsPouncing(leaping); -+ } -+ -+ @Override -+ public boolean isLeaping() { -+ return this.getHandle().isPouncing(); -+ } -+ -+ @Override -+ public void setDefending(boolean defending) { -+ this.getHandle().setDefending(defending); -+ } -+ -+ @Override -+ public boolean isDefending() { -+ return this.getHandle().isDefending(); -+ } -+ -+ @Override -+ public void setFaceplanted(boolean faceplanted) { -+ this.getHandle().setFaceplanted(faceplanted); -+ } -+ // Paper end - Add more fox behavior API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java -index 2cec61a1bb050c1ef81c5fc3d0afafe9ff29d459..97fa4e1e70203194bd939618b2fad92665af6d59 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftGhast.java -@@ -28,4 +28,17 @@ public class CraftGhast extends CraftFlying implements Ghast, CraftEnemy { - public void setCharging(boolean flag) { - this.getHandle().setCharging(flag); - } -+ -+ // Paper start -+ @Override -+ public int getExplosionPower() { -+ return this.getHandle().getExplosionPower(); -+ } -+ -+ @Override -+ public void setExplosionPower(int explosionPower) { -+ com.google.common.base.Preconditions.checkArgument(explosionPower >= 0 && explosionPower <= 127, "The explosion power has to be between 0 and 127"); -+ this.getHandle().setExplosionPower(explosionPower); -+ } -+ // 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 a4a30f52f45bf91dc88d53f5d6a376ed739d09eb..6020c0c164595db4e2001edf0c1fbe99ed87682d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -128,6 +128,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - } - } - -+ // Paper start - entity heal API -+ @Override -+ public void heal(final double amount, final org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason reason) { -+ this.getHandle().heal((float) amount, reason); -+ } -+ // Paper end - entity heal API -+ - @Override - public double getAbsorptionAmount() { - return this.getHandle().getAbsorptionAmount(); -@@ -939,14 +946,29 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - - @Override - public boolean isInvisible() { -- return this.getHandle().isInvisible(); -+ return super.isInvisible(); // Paper - move invisibility up to Entity - diff on change - } - - @Override - public void setInvisible(boolean invisible) { -- this.getHandle().persistentInvisibility = invisible; -- this.getHandle().setSharedFlag(5, invisible); -+ super.setInvisible(invisible); // Paper - move invisibility up to Entity - } -+ // Paper start -+ @Override -+ public float getSidewaysMovement() { -+ return this.getHandle().xxa; -+ } -+ -+ @Override -+ public float getForwardsMovement() { -+ return this.getHandle().zza; -+ } -+ -+ @Override -+ public float getUpwardsMovement() { -+ return this.getHandle().yya; -+ } -+ // Paper end - - // Paper start - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java -index bf297388c75521266c93580a9caafe6bad70ab45..351f42842b780d053cd2e5bad9ae299449141b10 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java -@@ -58,4 +58,36 @@ public class CraftLlama extends CraftChestedHorse implements Llama, com.destroys - public String toString() { - return "CraftLlama"; - } -+ -+ // Paper start -+ @Override -+ public boolean inCaravan() { -+ return this.getHandle().inCaravan(); -+ } -+ -+ @Override -+ public void joinCaravan(@org.jetbrains.annotations.NotNull Llama llama) { -+ this.getHandle().joinCaravan(((CraftLlama) llama).getHandle()); -+ } -+ -+ @Override -+ public void leaveCaravan() { -+ this.getHandle().leaveCaravan(); -+ } -+ -+ @Override -+ public boolean hasCaravanTail() { -+ return this.getHandle().hasCaravanTail(); -+ } -+ -+ @Override -+ public Llama getCaravanHead() { -+ return this.getHandle().getCaravanHead() == null ? null : (Llama) this.getHandle().getCaravanHead().getBukkitEntity(); -+ } -+ -+ @Override -+ public Llama getCaravanTail() { -+ return this.getHandle().caravanTail == null ? null : (Llama) this.getHandle().caravanTail.getBukkitEntity(); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java -index 17f5684cba9d3ed22d9925d1951520cc4751dfe2..3a3563a1bdbc0d84d973b3a04b50b78b4bc3d379 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java -@@ -33,4 +33,20 @@ public final class CraftMinecartHopper extends CraftMinecartContainer implements - public void setEnabled(boolean enabled) { - ((MinecartHopper) this.getHandle()).setEnabled(enabled); - } -+ // Paper start -+ @Override -+ public net.minecraft.world.entity.vehicle.MinecartHopper getHandle() { -+ return (net.minecraft.world.entity.vehicle.MinecartHopper) super.getHandle(); -+ } -+ -+ @Override -+ public int getPickupCooldown() { -+ throw new UnsupportedOperationException("Hopper minecarts don't have cooldowns"); -+ } -+ -+ @Override -+ public void setPickupCooldown(int cooldown) { -+ throw new UnsupportedOperationException("Hopper minecarts don't have cooldowns"); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -index bd739428a7e5e35ebcdb70cd187379b3d222339b..7cf42f62d91c131b1cab576979f85c58c3cecb3b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -@@ -146,4 +146,16 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { - return getHandle().getMaxHeadXRot(); - } - // Paper end -+ -+ // Paper start -+ @Override -+ public boolean isAggressive() { -+ return this.getHandle().isAggressive(); -+ } -+ -+ @Override -+ public void setAggressive(boolean aggressive) { -+ this.getHandle().setAggressive(aggressive); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPanda.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPanda.java -index 5467e4a74b70ff57b49d9e6bc686c493178f8511..01d104d91de9e1319d27e39d3f474318c7809486 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPanda.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPanda.java -@@ -41,6 +41,38 @@ public class CraftPanda extends CraftAnimals implements Panda { - this.getHandle().setHiddenGene(CraftPanda.toNms(gene)); - } - -+ // Paper start - Panda API -+ @Override -+ public void setSneezeTicks(int ticks) { -+ this.getHandle().setSneezeCounter(ticks); -+ } -+ -+ @Override -+ public int getSneezeTicks() { -+ return this.getHandle().getSneezeCounter(); -+ } -+ -+ @Override -+ public void setEatingTicks(int ticks) { -+ this.getHandle().setEatCounter(ticks); -+ } -+ -+ @Override -+ public int getEatingTicks() { -+ return this.getHandle().getEatCounter(); -+ } -+ -+ @Override -+ public void setUnhappyTicks(int ticks) { -+ this.getHandle().setUnhappyCounter(ticks); -+ } -+ -+ @Override -+ public Gene getCombinedGene() { -+ return CraftPanda.fromNms(this.getHandle().getVariant()); -+ } -+ // Paper end - Panda API -+ - @Override - public boolean isRolling() { - return this.getHandle().isRolling(); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java -index 9304e201db1ec96d0916aa8ea781f3e4bc7991e6..83e77c6d287d8e239d2f55f3e9f19ef74946be7c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java -@@ -44,5 +44,17 @@ public class CraftPhantom extends CraftFlying implements Phantom, CraftEnemy { - public void setShouldBurnInDay(boolean shouldBurnInDay) { - getHandle().setShouldBurnInDay(shouldBurnInDay); - } -+ -+ @Override -+ public org.bukkit.Location getAnchorLocation() { -+ net.minecraft.core.BlockPos pos = this.getHandle().anchorPoint; -+ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), pos); -+ } -+ -+ @Override -+ public void setAnchorLocation(org.bukkit.Location location) { -+ com.google.common.base.Preconditions.checkArgument(location != null, "location cannot be null"); -+ this.getHandle().anchorPoint = io.papermc.paper.util.MCUtil.toBlockPosition(location); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java -index f5ecb8c1dc92e5a4b123effd2859123b17a586d3..5124a383b60b2c8de89fa992547d0c61db760c21 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java -@@ -84,4 +84,37 @@ public class CraftPiglin extends CraftPiglinAbstract implements Piglin, com.dest - public String toString() { - return "CraftPiglin"; - } -+ // Paper start -+ @Override -+ public void setChargingCrossbow(boolean chargingCrossbow) { -+ this.getHandle().setChargingCrossbow(chargingCrossbow); -+ } -+ -+ @Override -+ public boolean isChargingCrossbow() { -+ return this.getHandle().isChargingCrossbow(); -+ } -+ -+ @Override -+ public void setDancing(boolean dancing) { -+ if (dancing) { -+ this.getHandle().getBrain().setMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.DANCING, true); -+ this.getHandle().getBrain().setMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.CELEBRATE_LOCATION, this.getHandle().getOnPos()); -+ } else { -+ this.getHandle().getBrain().eraseMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.DANCING); -+ this.getHandle().getBrain().eraseMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.CELEBRATE_LOCATION); -+ } -+ } -+ -+ @Override -+ public void setDancing(long duration) { -+ this.getHandle().getBrain().setMemoryWithExpiry(net.minecraft.world.entity.ai.memory.MemoryModuleType.DANCING, true, duration); -+ this.getHandle().getBrain().setMemoryWithExpiry(net.minecraft.world.entity.ai.memory.MemoryModuleType.CELEBRATE_LOCATION, this.getHandle().getOnPos(), duration); -+ } -+ -+ @Override -+ public boolean isDancing() { -+ return this.getHandle().isDancing(); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPolarBear.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPolarBear.java -index c7aec6f28e5d3546235b30f6b1112440a76163c5..fe075cfdf3097d6cb768e71b8cc360abb8eaf367 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPolarBear.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPolarBear.java -@@ -17,4 +17,16 @@ public class CraftPolarBear extends CraftAnimals implements PolarBear { - public String toString() { - return "CraftPolarBear"; - } -+ -+ // Paper start -+ @Override -+ public boolean isStanding() { -+ return this.getHandle().isStanding(); -+ } -+ -+ @Override -+ public void setStanding(boolean standing) { -+ this.getHandle().setStanding(standing); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java -index 6b48b117a9cba12aae055c0ea981dfb5bc03a86e..519ef701a7d6534f7cb516f6296b95ee521f661d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftRabbit.java -@@ -29,4 +29,15 @@ public class CraftRabbit extends CraftAnimals implements Rabbit { - public void setRabbitType(Type type) { - this.getHandle().setVariant(net.minecraft.world.entity.animal.Rabbit.Variant.values()[type.ordinal()]); - } -+ // Paper start -+ @Override -+ public void setMoreCarrotTicks(int ticks) { -+ this.getHandle().moreCarrotTicks = ticks; -+ } -+ -+ @Override -+ public int getMoreCarrotTicks() { -+ return this.getHandle().moreCarrotTicks; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftRavager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftRavager.java -index cae59f77c704a5b9515dc4917ed5fdc89631ecfb..09796ce15658e3f7c223a265a547a51ee729ed40 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftRavager.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftRavager.java -@@ -18,4 +18,35 @@ public class CraftRavager extends CraftRaider implements Ravager { - public String toString() { - return "CraftRavager"; - } -+ // Paper start - Missing Entity Behavior -+ @Override -+ public int getAttackTicks() { -+ return this.getHandle().getAttackTick(); -+ } -+ -+ @Override -+ public void setAttackTicks(int ticks) { -+ this.getHandle().attackTick = ticks; -+ } -+ -+ @Override -+ public int getStunnedTicks() { -+ return this.getHandle().getStunnedTick(); -+ } -+ -+ @Override -+ public void setStunnedTicks(int ticks) { -+ this.getHandle().stunnedTick = ticks; -+ } -+ -+ @Override -+ public int getRoarTicks() { -+ return this.getHandle().getRoarTick(); -+ } -+ -+ @Override -+ public void setRoarTicks(int ticks) { -+ this.getHandle().roarTick = ticks; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSalmon.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSalmon.java -index 551c30cb0fb41dfe4a03663d34ecf9764566c215..7660cc21e936002ebb23510f0ec2b58d71e5157d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSalmon.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSalmon.java -@@ -4,7 +4,7 @@ import com.google.common.base.Preconditions; - import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.entity.Salmon; - --public class CraftSalmon extends CraftFish implements Salmon { -+public class CraftSalmon extends io.papermc.paper.entity.PaperSchoolableFish implements Salmon { // Paper - Schooling Fish API - - public CraftSalmon(CraftServer server, net.minecraft.world.entity.animal.Salmon entity) { - super(server, entity); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java -index 36ab282e2c4060bdea4e57f3ab9dfef9f6cd622c..a61aec087fa7cec27a803668bdc1b9e6eb336755 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java -@@ -67,4 +67,17 @@ public class CraftTNTPrimed extends CraftEntity implements TNTPrimed { - this.getHandle().owner = null; - } - } -+ -+ // Paper start -+ @Override -+ public void setBlockData(org.bukkit.block.data.BlockData data) { -+ com.google.common.base.Preconditions.checkArgument(data != null, "The visual block data of this tnt cannot be null. To reset it just set to the TNT default block data"); -+ this.getHandle().setBlockState(((org.bukkit.craftbukkit.block.data.CraftBlockData) data).getState()); -+ } -+ -+ @Override -+ public org.bukkit.block.data.BlockData getBlockData() { -+ return org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(this.getHandle().getBlockState()); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java -index 451a9bfd9b9b6945e224f1bb05c7951ed934b4e3..d7c6a0bbc5671ea8f2488230c94df5146a1e98b9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java -@@ -28,4 +28,15 @@ public class CraftTadpole extends CraftFish implements org.bukkit.entity.Tadpole - public void setAge(int age) { - this.getHandle().age = age; - } -+ // Paper start -+ @Override -+ public void setAgeLock(boolean lock) { -+ this.getHandle().ageLocked = lock; -+ } -+ -+ @Override -+ public boolean getAgeLock() { -+ return this.getHandle().ageLocked; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java -index 33d6e8121755ad6cddacb4fc69e795f9831c27bd..e374b9f40eddca13b30855d25a2030f8df98138f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java -@@ -31,4 +31,27 @@ public class CraftTrident extends CraftAbstractArrow implements Trident { - public String toString() { - return "CraftTrident"; - } -+ -+ // Paper start -+ @Override -+ public boolean hasGlint() { -+ return this.getHandle().isFoil(); -+ } -+ -+ @Override -+ public void setGlint(boolean glint) { -+ this.getHandle().setFoil(glint); -+ } -+ -+ @Override -+ public int getLoyaltyLevel() { -+ return this.getHandle().getLoyalty(); -+ } -+ -+ @Override -+ public void setLoyaltyLevel(int loyaltyLevel) { -+ 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); -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTropicalFish.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTropicalFish.java -index e3bde6d1c0e03407af1382a61748470063bb2e18..9e53c30801c700719c78c0fd521fd615c94e02c8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTropicalFish.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTropicalFish.java -@@ -7,7 +7,7 @@ import org.bukkit.craftbukkit.CraftServer; - import org.bukkit.entity.TropicalFish; - import org.bukkit.entity.TropicalFish.Pattern; - --public class CraftTropicalFish extends CraftFish implements TropicalFish { -+public class CraftTropicalFish extends io.papermc.paper.entity.PaperSchoolableFish implements TropicalFish { // Paper - Schooling Fish API - - public CraftTropicalFish(CraftServer server, net.minecraft.world.entity.animal.TropicalFish entity) { - super(server, entity); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java -index 1cfbe9c476f4a254edf3edf4b70696bbaba78558..e9ec3455eabc473e104b5342a615a38c1ac25a4f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java -@@ -29,6 +29,26 @@ public class CraftVex extends CraftMonster implements Vex { - public void setSummoner(org.bukkit.entity.Mob summoner) { - getHandle().setOwner(summoner == null ? null : ((CraftMob) summoner).getHandle()); - } -+ -+ @Override -+ public boolean hasLimitedLifetime() { -+ return this.getHandle().hasLimitedLife; -+ } -+ -+ @Override -+ public void setLimitedLifetime(boolean hasLimitedLifetime) { -+ this.getHandle().hasLimitedLife = hasLimitedLifetime; -+ } -+ -+ @Override -+ public int getLimitedLifetimeTicks() { -+ return this.getHandle().limitedLifeTicks; -+ } -+ -+ @Override -+ public void setLimitedLifetimeTicks(int ticks) { -+ this.getHandle().limitedLifeTicks = ticks; -+ } - // Paper end - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java -index e2a0c11867abee6add8775259c54f2052de7b1ad..3aa23d9f22d5cd22231293fd7d1ca4cb79eb7cb3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java -@@ -60,13 +60,20 @@ public class CraftVillagerZombie extends CraftZombie implements ZombieVillager { - - @Override - public void setConversionTime(int time) { -+ // Paper start - missing entity behaviour api - converting without entity event -+ this.setConversionTime(time, true); -+ } -+ -+ @Override -+ public void setConversionTime(int time, boolean broadcastEntityEvent) { -+ // Paper end - missing entity behaviour api - converting without entity event - if (time < 0) { - this.getHandle().villagerConversionTime = -1; - this.getHandle().getEntityData().set(net.minecraft.world.entity.monster.ZombieVillager.DATA_CONVERTING_ID, false); - this.getHandle().conversionStarter = null; - this.getHandle().removeEffect(MobEffects.DAMAGE_BOOST, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); - } else { -- this.getHandle().startConverting(null, time); -+ this.getHandle().startConverting(null, time, broadcastEntityEvent); // Paper - missing entity behaviour api - converting without entity event - } - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java -index 0e597394a3dd08f022614fc9777302fea581eb55..3cceefa0d6278924a19641a49bdf16bcdacb2233 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java -@@ -49,5 +49,25 @@ public class CraftWanderingTrader extends CraftAbstractVillager implements Wande - public boolean canDrinkMilk() { - return getHandle().canDrinkMilk; - } -+ -+ @Override -+ public org.bukkit.Location getWanderingTowards() { -+ net.minecraft.core.BlockPos pos = this.getHandle().getWanderTarget(); -+ if (pos == null) { -+ return null; -+ } -+ -+ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level(), pos); -+ } -+ -+ @Override -+ public void setWanderingTowards(org.bukkit.Location location) { -+ net.minecraft.core.BlockPos pos = null; -+ if (location != null) { -+ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); -+ } -+ -+ this.getHandle().setWanderTarget(pos); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWarden.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWarden.java -index 794e4fe0a3fbd967f665b2707865c15491370c76..c284eb96a1e330078076cbe61f0f6e2ff4ed89bd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWarden.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWarden.java -@@ -37,6 +37,13 @@ public class CraftWarden extends CraftMonster implements org.bukkit.entity.Warde - return this.getHandle().getAngerManagement().getActiveAnger(((CraftEntity) entity).getHandle()); - } - -+ // Paper start -+ @Override -+ public int getHighestAnger() { -+ return this.getHandle().getAngerManagement().getActiveAnger(null); -+ } -+ // Paper end -+ - @Override - public void increaseAnger(Entity entity, int increase) { - Preconditions.checkArgument(entity != null, "Entity cannot be null"); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java -index 1113533d281ed159bb735040fb1f913482debf3a..7881c6253c1d652c0c0d54a9a8accdf0a1ff0f3e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java -@@ -67,4 +67,36 @@ public class CraftWither extends CraftMonster implements Wither, com.destroystok - - this.getHandle().setInvulnerableTicks(ticks); - } -+ -+ // Paper start -+ @Override -+ public boolean isCharged() { -+ return getHandle().isPowered(); -+ } -+ -+ @Override -+ public int getInvulnerableTicks() { -+ return getHandle().getInvulnerableTicks(); -+ } -+ -+ @Override -+ public void setInvulnerableTicks(int ticks) { -+ getHandle().setInvulnerableTicks(ticks); -+ } -+ -+ @Override -+ public boolean canTravelThroughPortals() { -+ return getHandle().canUsePortal(false); -+ } -+ -+ @Override -+ public void setCanTravelThroughPortals(boolean value) { -+ getHandle().setCanTravelThroughPortals(value); -+ } -+ -+ @Override -+ public void enterInvulnerabilityPhase() { -+ this.getHandle().makeInvulnerable(); -+ } -+ // Paper end - } diff --git a/patches/server/0551-Fix-return-value-of-Block-applyBoneMeal-always-being.patch b/patches/server/0551-Fix-return-value-of-Block-applyBoneMeal-always-being.patch deleted file mode 100644 index 40cc161932..0000000000 --- a/patches/server/0551-Fix-return-value-of-Block-applyBoneMeal-always-being.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Mon, 28 Jun 2021 18:16:52 -0700 -Subject: [PATCH] Fix return value of Block#applyBoneMeal always being false - - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 54fb380a6896731a18c0100722d12099e590cbc9..9c8aac69f01db647e20d49d272ccc107a7edceaf 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -558,7 +558,7 @@ public class CraftBlock implements Block { - } - } - -- return result == InteractionResult.SUCCESS && (event == null || !event.isCancelled()); -+ return result == InteractionResult.CONSUME && (event == null || !event.isCancelled()); // Paper - CONSUME is returned on success server-side (see BoneMealItem.applyBoneMeal and InteractionResult.sidedSuccess(boolean)) - } - - @Override diff --git a/patches/server/0551-Use-getChunkIfLoadedImmediately-in-places.patch b/patches/server/0551-Use-getChunkIfLoadedImmediately-in-places.patch new file mode 100644 index 0000000000..908ee6c4ee --- /dev/null +++ b/patches/server/0551-Use-getChunkIfLoadedImmediately-in-places.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 8 Jul 2019 00:13:36 -0700 +Subject: [PATCH] Use getChunkIfLoadedImmediately in places + +This prevents us from hitting chunk loads for chunks at or less-than +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 4982cdfbceb829e06f26eb927e1176bb4a975336..dc3d6bbbd79a0decc134f792d884962534717c0e 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -233,7 +233,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent + + public LevelChunk getChunkIfLoaded(int x, int z) { +- return this.chunkSource.getChunk(x, z, false); ++ return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately + } + + @Override +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 2f82f77ba6530dcdb98037aa627ef3cead758b2e..68cee32833a3d683852e67e3727d62b84fa60cc4 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 { + public CraftServer getCraftServer() { + return (CraftServer) Bukkit.getServer(); + } ++ // Paper start - Use getChunkIfLoadedImmediately ++ @Override ++ public boolean hasChunk(int chunkX, int chunkZ) { ++ return this.getChunkIfLoaded(chunkX, chunkZ) != null; ++ } ++ // Paper end - Use getChunkIfLoadedImmediately ++ + + public abstract ResourceKey getTypeKey(); + +diff --git a/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java b/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java +index 13b34e89bd3e55df1bb1d4d0cf013bafae43f502..df6c97be1b278c97a20390be5d3e60f429383702 100644 +--- a/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java ++++ b/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java +@@ -56,7 +56,7 @@ public class GameEventDispatcher { + + for (int l1 = j; l1 <= i1; ++l1) { + for (int i2 = l; i2 <= k1; ++i2) { +- LevelChunk chunk = this.level.getChunkSource().getChunkNow(l1, i2); ++ LevelChunk chunk = (LevelChunk) this.level.getChunkIfLoadedImmediately(l1, i2); // Paper - Use getChunkIfLoadedImmediately + + if (chunk != null) { + for (int j2 = k; j2 <= j1; ++j2) { diff --git a/patches/server/0552-Fix-commands-from-signs-not-firing-command-events.patch b/patches/server/0552-Fix-commands-from-signs-not-firing-command-events.patch new file mode 100644 index 0000000000..c851f91672 --- /dev/null +++ b/patches/server/0552-Fix-commands-from-signs-not-firing-command-events.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 9 Jul 2021 13:50:48 -0700 +Subject: [PATCH] Fix commands from signs not firing command events + +This patch changes sign command logic so that `run_command` click events: + - are logged to the console + - fire PlayerCommandPreprocessEvent + - work with double-slash commands like `//wand` + - sends failure messages to the player who clicked the sign + +diff --git a/src/main/java/io/papermc/paper/commands/DelegatingCommandSource.java b/src/main/java/io/papermc/paper/commands/DelegatingCommandSource.java +new file mode 100644 +index 0000000000000000000000000000000000000000..01a2bc1feec808790bb93618ce46adb9bea5a9c8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/commands/DelegatingCommandSource.java +@@ -0,0 +1,42 @@ ++package io.papermc.paper.commands; ++ ++import net.minecraft.commands.CommandSource; ++import net.minecraft.commands.CommandSourceStack; ++import net.minecraft.network.chat.Component; ++import org.bukkit.command.CommandSender; ++ ++import java.util.UUID; ++ ++public class DelegatingCommandSource implements CommandSource { ++ ++ private final CommandSource delegate; ++ ++ public DelegatingCommandSource(CommandSource delegate) { ++ this.delegate = delegate; ++ } ++ ++ @Override ++ public void sendSystemMessage(Component message) { ++ delegate.sendSystemMessage(message); ++ } ++ ++ @Override ++ public boolean acceptsSuccess() { ++ return delegate.acceptsSuccess(); ++ } ++ ++ @Override ++ public boolean acceptsFailure() { ++ return delegate.acceptsFailure(); ++ } ++ ++ @Override ++ public boolean shouldInformAdmins() { ++ return delegate.shouldInformAdmins(); ++ } ++ ++ @Override ++ public CommandSender getBukkitSender(CommandSourceStack wrapper) { ++ return delegate.getBukkitSender(wrapper); ++ } ++} +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 9861388bdca8d32b7e9a49a251088c98283d8234..86550d200922ee313019a21fe593c594c967f28b 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 +@@ -274,7 +274,17 @@ public class SignBlockEntity extends BlockEntity { + ClickEvent chatclickable = chatmodifier.getClickEvent(); + + if (chatclickable != null && chatclickable.getAction() == ClickEvent.Action.RUN_COMMAND) { +- player.getServer().getCommands().performPrefixedCommand(this.createCommandSourceStack(player, world, pos), chatclickable.getValue()); ++ // Paper start - Fix commands from signs not firing command events ++ String command = chatclickable.getValue().startsWith("/") ? chatclickable.getValue() : "/" + chatclickable.getValue(); ++ if (org.spigotmc.SpigotConfig.logCommands) { ++ LOGGER.info("{} issued server command: {}", player.getScoreboardName(), command); ++ } ++ io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent((org.bukkit.entity.Player) player.getBukkitEntity(), command, new org.bukkit.craftbukkit.util.LazyPlayerSet(player.getServer()), (org.bukkit.block.Sign) CraftBlock.at(this.level, this.worldPosition).getState(), front ? Side.FRONT : Side.BACK); ++ if (!event.callEvent()) { ++ return false; ++ } ++ player.getServer().getCommands().performPrefixedCommand(this.createCommandSourceStack(((org.bukkit.craftbukkit.entity.CraftPlayer) event.getPlayer()).getHandle(), world, pos), event.getMessage()); ++ // Paper end - Fix commands from signs not firing command events + flag1 = true; + } + } +@@ -314,8 +324,23 @@ public class SignBlockEntity extends BlockEntity { + String s = player == null ? "Sign" : player.getName().getString(); + Object object = player == null ? Component.literal("Sign") : player.getDisplayName(); + +- // CraftBukkit - commandSource +- return new CommandSourceStack(this.commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel) world, 2, s, (Component) object, world.getServer(), player); ++ // Paper start - Fix commands from signs not firing command events ++ CommandSource commandSource = this.level.paperConfig().misc.showSignClickCommandFailureMsgsToPlayer ? new io.papermc.paper.commands.DelegatingCommandSource(this.commandSource) { ++ @Override ++ public void sendSystemMessage(Component message) { ++ if (player instanceof final ServerPlayer serverPlayer) { ++ serverPlayer.sendSystemMessage(message); ++ } ++ } ++ ++ @Override ++ public boolean acceptsFailure() { ++ return true; ++ } ++ } : this.commandSource; ++ // Paper end - Fix commands from signs not firing command events ++ // CraftBukkit - this ++ return new CommandSourceStack(commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel) world, 2, s, (Component) object, world.getServer(), player); // Paper - Fix commands from signs not firing command events + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java +index d113e54a30db16e2ad955170df6030d15de530d6..21b6f90cf5bd7087d1a0f512289d971f2c3e1afa 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java +@@ -61,7 +61,7 @@ public class BukkitCommandWrapper implements com.mojang.brigadier.Command -Date: Mon, 8 Jul 2019 00:13:36 -0700 -Subject: [PATCH] Use getChunkIfLoadedImmediately in places - -This prevents us from hitting chunk loads for chunks at or less-than -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 c05ccab70bd81d536f93352f30aab9b07b90876a..93656336af194994f59072fa89bfc338d89d76af 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -233,7 +233,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent - - public LevelChunk getChunkIfLoaded(int x, int z) { -- return this.chunkSource.getChunk(x, z, false); -+ return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 2f82f77ba6530dcdb98037aa627ef3cead758b2e..68cee32833a3d683852e67e3727d62b84fa60cc4 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 { - public CraftServer getCraftServer() { - return (CraftServer) Bukkit.getServer(); - } -+ // Paper start - Use getChunkIfLoadedImmediately -+ @Override -+ public boolean hasChunk(int chunkX, int chunkZ) { -+ return this.getChunkIfLoaded(chunkX, chunkZ) != null; -+ } -+ // Paper end - Use getChunkIfLoadedImmediately -+ - - public abstract ResourceKey getTypeKey(); - -diff --git a/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java b/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java -index 13b34e89bd3e55df1bb1d4d0cf013bafae43f502..df6c97be1b278c97a20390be5d3e60f429383702 100644 ---- a/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java -+++ b/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java -@@ -56,7 +56,7 @@ public class GameEventDispatcher { - - for (int l1 = j; l1 <= i1; ++l1) { - for (int i2 = l; i2 <= k1; ++i2) { -- LevelChunk chunk = this.level.getChunkSource().getChunkNow(l1, i2); -+ LevelChunk chunk = (LevelChunk) this.level.getChunkIfLoadedImmediately(l1, i2); // Paper - Use getChunkIfLoadedImmediately - - if (chunk != null) { - for (int j2 = k; j2 <= j1; ++j2) { diff --git a/patches/server/0553-Add-PlayerArmSwingEvent.patch b/patches/server/0553-Add-PlayerArmSwingEvent.patch new file mode 100644 index 0000000000..dd3c00cbf0 --- /dev/null +++ b/patches/server/0553-Add-PlayerArmSwingEvent.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 12 Mar 2021 19:22:21 -0800 +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 8f1188bd5e9e1ae7e5318674038c2d7f87d743b7..176bf8692e19abe0a24df3be28431b438f465613 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2488,7 +2488,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } // Paper end - Call interact event + + // Arm swing animation +- PlayerAnimationEvent event = new PlayerAnimationEvent(this.getCraftPlayer(), (packet.getHand() == InteractionHand.MAIN_HAND) ? PlayerAnimationType.ARM_SWING : PlayerAnimationType.OFF_ARM_SWING); ++ io.papermc.paper.event.player.PlayerArmSwingEvent event = new io.papermc.paper.event.player.PlayerArmSwingEvent(this.getCraftPlayer(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(packet.getHand())); // Paper - Add PlayerArmSwingEvent + this.cserver.getPluginManager().callEvent(event); + + if (event.isCancelled()) return; diff --git a/patches/server/0553-Fix-commands-from-signs-not-firing-command-events.patch b/patches/server/0553-Fix-commands-from-signs-not-firing-command-events.patch deleted file mode 100644 index c851f91672..0000000000 --- a/patches/server/0553-Fix-commands-from-signs-not-firing-command-events.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 9 Jul 2021 13:50:48 -0700 -Subject: [PATCH] Fix commands from signs not firing command events - -This patch changes sign command logic so that `run_command` click events: - - are logged to the console - - fire PlayerCommandPreprocessEvent - - work with double-slash commands like `//wand` - - sends failure messages to the player who clicked the sign - -diff --git a/src/main/java/io/papermc/paper/commands/DelegatingCommandSource.java b/src/main/java/io/papermc/paper/commands/DelegatingCommandSource.java -new file mode 100644 -index 0000000000000000000000000000000000000000..01a2bc1feec808790bb93618ce46adb9bea5a9c8 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/commands/DelegatingCommandSource.java -@@ -0,0 +1,42 @@ -+package io.papermc.paper.commands; -+ -+import net.minecraft.commands.CommandSource; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.network.chat.Component; -+import org.bukkit.command.CommandSender; -+ -+import java.util.UUID; -+ -+public class DelegatingCommandSource implements CommandSource { -+ -+ private final CommandSource delegate; -+ -+ public DelegatingCommandSource(CommandSource delegate) { -+ this.delegate = delegate; -+ } -+ -+ @Override -+ public void sendSystemMessage(Component message) { -+ delegate.sendSystemMessage(message); -+ } -+ -+ @Override -+ public boolean acceptsSuccess() { -+ return delegate.acceptsSuccess(); -+ } -+ -+ @Override -+ public boolean acceptsFailure() { -+ return delegate.acceptsFailure(); -+ } -+ -+ @Override -+ public boolean shouldInformAdmins() { -+ return delegate.shouldInformAdmins(); -+ } -+ -+ @Override -+ public CommandSender getBukkitSender(CommandSourceStack wrapper) { -+ return delegate.getBukkitSender(wrapper); -+ } -+} -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 9861388bdca8d32b7e9a49a251088c98283d8234..86550d200922ee313019a21fe593c594c967f28b 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 -@@ -274,7 +274,17 @@ public class SignBlockEntity extends BlockEntity { - ClickEvent chatclickable = chatmodifier.getClickEvent(); - - if (chatclickable != null && chatclickable.getAction() == ClickEvent.Action.RUN_COMMAND) { -- player.getServer().getCommands().performPrefixedCommand(this.createCommandSourceStack(player, world, pos), chatclickable.getValue()); -+ // Paper start - Fix commands from signs not firing command events -+ String command = chatclickable.getValue().startsWith("/") ? chatclickable.getValue() : "/" + chatclickable.getValue(); -+ if (org.spigotmc.SpigotConfig.logCommands) { -+ LOGGER.info("{} issued server command: {}", player.getScoreboardName(), command); -+ } -+ io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent((org.bukkit.entity.Player) player.getBukkitEntity(), command, new org.bukkit.craftbukkit.util.LazyPlayerSet(player.getServer()), (org.bukkit.block.Sign) CraftBlock.at(this.level, this.worldPosition).getState(), front ? Side.FRONT : Side.BACK); -+ if (!event.callEvent()) { -+ return false; -+ } -+ player.getServer().getCommands().performPrefixedCommand(this.createCommandSourceStack(((org.bukkit.craftbukkit.entity.CraftPlayer) event.getPlayer()).getHandle(), world, pos), event.getMessage()); -+ // Paper end - Fix commands from signs not firing command events - flag1 = true; - } - } -@@ -314,8 +324,23 @@ public class SignBlockEntity extends BlockEntity { - String s = player == null ? "Sign" : player.getName().getString(); - Object object = player == null ? Component.literal("Sign") : player.getDisplayName(); - -- // CraftBukkit - commandSource -- return new CommandSourceStack(this.commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel) world, 2, s, (Component) object, world.getServer(), player); -+ // Paper start - Fix commands from signs not firing command events -+ CommandSource commandSource = this.level.paperConfig().misc.showSignClickCommandFailureMsgsToPlayer ? new io.papermc.paper.commands.DelegatingCommandSource(this.commandSource) { -+ @Override -+ public void sendSystemMessage(Component message) { -+ if (player instanceof final ServerPlayer serverPlayer) { -+ serverPlayer.sendSystemMessage(message); -+ } -+ } -+ -+ @Override -+ public boolean acceptsFailure() { -+ return true; -+ } -+ } : this.commandSource; -+ // Paper end - Fix commands from signs not firing command events -+ // CraftBukkit - this -+ return new CommandSourceStack(commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel) world, 2, s, (Component) object, world.getServer(), player); // Paper - Fix commands from signs not firing command events - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java -index d113e54a30db16e2ad955170df6030d15de530d6..21b6f90cf5bd7087d1a0f512289d971f2c3e1afa 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java -@@ -61,7 +61,7 @@ public class BukkitCommandWrapper implements com.mojang.brigadier.Command -Date: Fri, 12 Mar 2021 19:22:21 -0800 -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 8f1188bd5e9e1ae7e5318674038c2d7f87d743b7..176bf8692e19abe0a24df3be28431b438f465613 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2488,7 +2488,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } // Paper end - Call interact event - - // Arm swing animation -- PlayerAnimationEvent event = new PlayerAnimationEvent(this.getCraftPlayer(), (packet.getHand() == InteractionHand.MAIN_HAND) ? PlayerAnimationType.ARM_SWING : PlayerAnimationType.OFF_ARM_SWING); -+ io.papermc.paper.event.player.PlayerArmSwingEvent event = new io.papermc.paper.event.player.PlayerArmSwingEvent(this.getCraftPlayer(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(packet.getHand())); // Paper - Add PlayerArmSwingEvent - this.cserver.getPluginManager().callEvent(event); - - if (event.isCancelled()) return; diff --git a/patches/server/0554-Fix-kick-event-leave-message-not-being-sent.patch b/patches/server/0554-Fix-kick-event-leave-message-not-being-sent.patch new file mode 100644 index 0000000000..3ea1b881c0 --- /dev/null +++ b/patches/server/0554-Fix-kick-event-leave-message-not-being-sent.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 7 Jul 2021 16:19:41 -0700 +Subject: [PATCH] Fix kick event leave message not being sent + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 33974faafabe763ac7d932f2fdb814ea914ccf88..2d8760216b63e0858088cc5f505406fca48e0151 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -316,7 +316,6 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + public boolean joining = true; + public boolean sentListPacket = false; + public boolean supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready +- public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent + // CraftBukkit end + public boolean isRealPlayer; // Paper + public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent +diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +index 59d20fd62e850a38380d877cef95ed69cb46ecbd..fc242acade3ff06c9213428cde103cf078216382 100644 +--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +@@ -116,6 +116,11 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + + @Override + public void onDisconnect(DisconnectionDetails info) { ++ // Paper start - Fix kick event leave message not being sent ++ this.onDisconnect(info, null); ++ } ++ public void onDisconnect(DisconnectionDetails info, @Nullable net.kyori.adventure.text.Component quitMessage) { ++ // Paper end - Fix kick event leave message not being sent + if (this.isSingleplayerOwner()) { + ServerCommonPacketListenerImpl.LOGGER.info("Stopping singleplayer server as player logged out"); + this.server.halt(false); +@@ -386,18 +391,17 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + // Do not kick the player + return; + } +- this.player.kickLeaveMessage = event.getLeaveMessage(); // CraftBukkit - SPIGOT-3034: Forward leave message to PlayerQuitEvent + // Send the possibly modified leave message +- this.disconnect0(new DisconnectionDetails(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.reason()), disconnectionInfo.report(), disconnectionInfo.bugReportLink())); // Paper - Adventure ++ this.disconnect0(new DisconnectionDetails(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.reason()), disconnectionInfo.report(), disconnectionInfo.bugReportLink()), event.leaveMessage()); // Paper - Adventure & use kick event leave message + } + +- private void disconnect0(DisconnectionDetails disconnectiondetails) { ++ private void disconnect0(DisconnectionDetails disconnectiondetails, @Nullable net.kyori.adventure.text.Component leaveMessage) { // Paper - use kick event leave message + // CraftBukkit end + this.player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.KICKED; // Paper - Add API for quit reason + this.connection.send(new ClientboundDisconnectPacket(disconnectiondetails.reason()), PacketSendListener.thenRun(() -> { + this.connection.disconnect(disconnectiondetails); + })); +- this.onDisconnect(disconnectiondetails); // CraftBukkit - fire quit instantly ++ this.onDisconnect(disconnectiondetails, leaveMessage); // CraftBukkit - fire quit instantly // Paper - use kick event leave message + this.connection.setReadOnly(); + 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 176bf8692e19abe0a24df3be28431b438f465613..fee3bcc109f77b2caaffe95c6bc181457018017d 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1975,6 +1975,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + @Override + public void onDisconnect(DisconnectionDetails info) { ++ // Paper start - Fix kick event leave message not being sent ++ this.onDisconnect(info, null); ++ } ++ @Override ++ public void onDisconnect(DisconnectionDetails info, @Nullable net.kyori.adventure.text.Component quitMessage) { ++ // Paper end - Fix kick event leave message not being sent + // CraftBukkit start - Rarely it would send a disconnect line twice + if (this.processedDisconnect) { + return; +@@ -1983,11 +1989,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + // CraftBukkit end + ServerGamePacketListenerImpl.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), info.reason().getString()); +- this.removePlayerFromWorld(); +- super.onDisconnect(info); ++ this.removePlayerFromWorld(quitMessage); // Paper - Fix kick event leave message not being sent ++ super.onDisconnect(info, quitMessage); // Paper - Fix kick event leave message not being sent + } + ++ // Paper start - Fix kick event leave message not being sent + private void removePlayerFromWorld() { ++ this.removePlayerFromWorld(null); ++ } ++ ++ private void removePlayerFromWorld(@Nullable net.kyori.adventure.text.Component quitMessage) { ++ // Paper end - Fix kick event leave message not being sent + this.chatMessageChain.close(); + // CraftBukkit start - Replace vanilla quit message handling with our own. + /* +@@ -1997,7 +2009,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + this.player.disconnect(); + // Paper start - Adventure +- net.kyori.adventure.text.Component quitMessage = this.server.getPlayerList().remove(this.player); ++ quitMessage = quitMessage == null ? this.server.getPlayerList().remove(this.player) : this.server.getPlayerList().remove(this.player, quitMessage); // Paper - pass in quitMessage to fix kick message not being used + if ((quitMessage != null) && !quitMessage.equals(net.kyori.adventure.text.Component.empty())) { + 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 0dbbf067bab9f2ceb5994a1d9a411e2c1824ad16..5b6d2080a1e8f8fbc7334071011415b9cb9b4621 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -510,6 +510,11 @@ public abstract class PlayerList { + } + + public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer) { // CraftBukkit - return string // Paper - return Component ++ // Paper start - Fix kick event leave message not being sent ++ return this.remove(entityplayer, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName()))); ++ } ++ public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer, net.kyori.adventure.text.Component leaveMessage) { ++ // Paper end - Fix kick event leave message not being sent + ServerLevel worldserver = entityplayer.serverLevel(); + + entityplayer.awardStat(Stats.LEAVE_GAME); +@@ -520,7 +525,7 @@ public abstract class PlayerList { + entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper - Inventory close reason + } + +- PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName())), entityplayer.quitReason); // Paper - Adventure & Add API for quit reason ++ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), leaveMessage, entityplayer.quitReason); // Paper - Adventure & Add API for quit reason + this.cserver.getPluginManager().callEvent(playerQuitEvent); + entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); + diff --git a/patches/server/0555-Don-t-apply-cramming-damage-to-players.patch b/patches/server/0555-Don-t-apply-cramming-damage-to-players.patch new file mode 100644 index 0000000000..19a62b06fd --- /dev/null +++ b/patches/server/0555-Don-t-apply-cramming-damage-to-players.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 +Date: Sun, 20 Jun 2021 16:35:42 +0100 +Subject: [PATCH] Don't apply cramming damage to players + +It does not make a lot of sense to damage players if they get crammed, + especially as the usecase of teleporting lots of players to the same + location isn't too uncommon and killing all those players isn't + really what one would expect to happen. + +For those who really want it a config option is provided. + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 2d8760216b63e0858088cc5f505406fca48e0151..ff678000823fef5f7b04b0023468a17ef1477758 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1805,7 +1805,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + + @Override + public boolean isInvulnerableTo(ServerLevel world, DamageSource source) { +- return super.isInvulnerableTo(world, source) || this.isChangingDimension() && !source.is(DamageTypes.ENDER_PEARL) || !this.hasClientLoaded(); ++ return (super.isInvulnerableTo(world, source) || this.isChangingDimension() && !source.is(DamageTypes.ENDER_PEARL) || !this.hasClientLoaded()) || (!this.level().paperConfig().collisions.allowPlayerCrammingDamage && source.is(DamageTypes.CRAMMING)); // Paper - disable player cramming + } + + @Override diff --git a/patches/server/0555-Fix-kick-event-leave-message-not-being-sent.patch b/patches/server/0555-Fix-kick-event-leave-message-not-being-sent.patch deleted file mode 100644 index d221b29c44..0000000000 --- a/patches/server/0555-Fix-kick-event-leave-message-not-being-sent.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 7 Jul 2021 16:19:41 -0700 -Subject: [PATCH] Fix kick event leave message not being sent - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index b1224b0ef12a746477047073f5bb94405871ce85..6c3ec21bb61e15becb35c01112770471c2364c5f 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -316,7 +316,6 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - public boolean joining = true; - public boolean sentListPacket = false; - public boolean supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready -- public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent - // CraftBukkit end - public boolean isRealPlayer; // Paper - public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent -diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 59d20fd62e850a38380d877cef95ed69cb46ecbd..fc242acade3ff06c9213428cde103cf078216382 100644 ---- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -116,6 +116,11 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - - @Override - public void onDisconnect(DisconnectionDetails info) { -+ // Paper start - Fix kick event leave message not being sent -+ this.onDisconnect(info, null); -+ } -+ public void onDisconnect(DisconnectionDetails info, @Nullable net.kyori.adventure.text.Component quitMessage) { -+ // Paper end - Fix kick event leave message not being sent - if (this.isSingleplayerOwner()) { - ServerCommonPacketListenerImpl.LOGGER.info("Stopping singleplayer server as player logged out"); - this.server.halt(false); -@@ -386,18 +391,17 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - // Do not kick the player - return; - } -- this.player.kickLeaveMessage = event.getLeaveMessage(); // CraftBukkit - SPIGOT-3034: Forward leave message to PlayerQuitEvent - // Send the possibly modified leave message -- this.disconnect0(new DisconnectionDetails(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.reason()), disconnectionInfo.report(), disconnectionInfo.bugReportLink())); // Paper - Adventure -+ this.disconnect0(new DisconnectionDetails(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.reason()), disconnectionInfo.report(), disconnectionInfo.bugReportLink()), event.leaveMessage()); // Paper - Adventure & use kick event leave message - } - -- private void disconnect0(DisconnectionDetails disconnectiondetails) { -+ private void disconnect0(DisconnectionDetails disconnectiondetails, @Nullable net.kyori.adventure.text.Component leaveMessage) { // Paper - use kick event leave message - // CraftBukkit end - this.player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.KICKED; // Paper - Add API for quit reason - this.connection.send(new ClientboundDisconnectPacket(disconnectiondetails.reason()), PacketSendListener.thenRun(() -> { - this.connection.disconnect(disconnectiondetails); - })); -- this.onDisconnect(disconnectiondetails); // CraftBukkit - fire quit instantly -+ this.onDisconnect(disconnectiondetails, leaveMessage); // CraftBukkit - fire quit instantly // Paper - use kick event leave message - this.connection.setReadOnly(); - 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 176bf8692e19abe0a24df3be28431b438f465613..fee3bcc109f77b2caaffe95c6bc181457018017d 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1975,6 +1975,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - @Override - public void onDisconnect(DisconnectionDetails info) { -+ // Paper start - Fix kick event leave message not being sent -+ this.onDisconnect(info, null); -+ } -+ @Override -+ public void onDisconnect(DisconnectionDetails info, @Nullable net.kyori.adventure.text.Component quitMessage) { -+ // Paper end - Fix kick event leave message not being sent - // CraftBukkit start - Rarely it would send a disconnect line twice - if (this.processedDisconnect) { - return; -@@ -1983,11 +1989,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - // CraftBukkit end - ServerGamePacketListenerImpl.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), info.reason().getString()); -- this.removePlayerFromWorld(); -- super.onDisconnect(info); -+ this.removePlayerFromWorld(quitMessage); // Paper - Fix kick event leave message not being sent -+ super.onDisconnect(info, quitMessage); // Paper - Fix kick event leave message not being sent - } - -+ // Paper start - Fix kick event leave message not being sent - private void removePlayerFromWorld() { -+ this.removePlayerFromWorld(null); -+ } -+ -+ private void removePlayerFromWorld(@Nullable net.kyori.adventure.text.Component quitMessage) { -+ // Paper end - Fix kick event leave message not being sent - this.chatMessageChain.close(); - // CraftBukkit start - Replace vanilla quit message handling with our own. - /* -@@ -1997,7 +2009,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - this.player.disconnect(); - // Paper start - Adventure -- net.kyori.adventure.text.Component quitMessage = this.server.getPlayerList().remove(this.player); -+ quitMessage = quitMessage == null ? this.server.getPlayerList().remove(this.player) : this.server.getPlayerList().remove(this.player, quitMessage); // Paper - pass in quitMessage to fix kick message not being used - if ((quitMessage != null) && !quitMessage.equals(net.kyori.adventure.text.Component.empty())) { - 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 0dbbf067bab9f2ceb5994a1d9a411e2c1824ad16..5b6d2080a1e8f8fbc7334071011415b9cb9b4621 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -510,6 +510,11 @@ public abstract class PlayerList { - } - - public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer) { // CraftBukkit - return string // Paper - return Component -+ // Paper start - Fix kick event leave message not being sent -+ return this.remove(entityplayer, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName()))); -+ } -+ public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer, net.kyori.adventure.text.Component leaveMessage) { -+ // Paper end - Fix kick event leave message not being sent - ServerLevel worldserver = entityplayer.serverLevel(); - - entityplayer.awardStat(Stats.LEAVE_GAME); -@@ -520,7 +525,7 @@ public abstract class PlayerList { - entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper - Inventory close reason - } - -- PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName())), entityplayer.quitReason); // Paper - Adventure & Add API for quit reason -+ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), leaveMessage, entityplayer.quitReason); // Paper - Adventure & Add API for quit reason - this.cserver.getPluginManager().callEvent(playerQuitEvent); - entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); - diff --git a/patches/server/0556-Don-t-apply-cramming-damage-to-players.patch b/patches/server/0556-Don-t-apply-cramming-damage-to-players.patch deleted file mode 100644 index 14f5ce16cf..0000000000 --- a/patches/server/0556-Don-t-apply-cramming-damage-to-players.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Sun, 20 Jun 2021 16:35:42 +0100 -Subject: [PATCH] Don't apply cramming damage to players - -It does not make a lot of sense to damage players if they get crammed, - especially as the usecase of teleporting lots of players to the same - location isn't too uncommon and killing all those players isn't - really what one would expect to happen. - -For those who really want it a config option is provided. - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 6c3ec21bb61e15becb35c01112770471c2364c5f..4c18d13fdc2221342adb390a6b68be871036c87c 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1805,7 +1805,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - - @Override - public boolean isInvulnerableTo(ServerLevel world, DamageSource source) { -- return super.isInvulnerableTo(world, source) || this.isChangingDimension() && !source.is(DamageTypes.ENDER_PEARL) || !this.hasClientLoaded(); -+ return (super.isInvulnerableTo(world, source) || this.isChangingDimension() && !source.is(DamageTypes.ENDER_PEARL) || !this.hasClientLoaded()) || (!this.level().paperConfig().collisions.allowPlayerCrammingDamage && source.is(DamageTypes.CRAMMING)); // Paper - disable player cramming - } - - @Override diff --git a/patches/server/0556-Rate-options-and-timings-for-sensors-and-behaviors.patch b/patches/server/0556-Rate-options-and-timings-for-sensors-and-behaviors.patch new file mode 100644 index 0000000000..3473ea4ceb --- /dev/null +++ b/patches/server/0556-Rate-options-and-timings-for-sensors-and-behaviors.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 +Date: Mon, 28 Jun 2021 22:38:29 +0100 +Subject: [PATCH] Rate options and timings for sensors and behaviors + +This adds config options to specify the tick rate for sensors + and behaviors of different entity types as well as timings + for those in order to be able to have some metrics as to which + ones might need tweaking. + +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..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,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; ++ // Paper end - configurable behavior tick rate and timings + + public Behavior(Map, MemoryStatus> requiredMemoryState) { + this(requiredMemoryState, 60); +@@ -27,6 +30,14 @@ public abstract class Behavior implements BehaviorContro + this.minDuration = minRunTime; + this.maxDuration = maxRunTime; + this.entryCondition = requiredMemoryState; ++ // Paper start - configurable behavior tick rate and timings ++ String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName(); ++ int lastSeparator = key.lastIndexOf('.'); ++ if (lastSeparator != -1) { ++ key = key.substring(lastSeparator + 1); ++ } ++ this.configKey = key.toLowerCase(java.util.Locale.ROOT); ++ // Paper end - configurable behavior tick rate and timings + } + + @Override +@@ -36,6 +47,12 @@ public abstract class Behavior implements BehaviorContro + + @Override + public final boolean tryStart(ServerLevel world, E entity, long time) { ++ // Paper start - configurable behavior tick rate and timings ++ int tickRate = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.behavior.get(entity.getType(), this.configKey), -1); ++ if (tickRate > -1 && time < this.endTimestamp + tickRate) { ++ return false; ++ } ++ // Paper end - configurable behavior tick rate and timings + 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); +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..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,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; ++ // Paper end + + public Sensor(int senseInterval) { ++ // Paper start - configurable sensor tick rate and timings ++ String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName(); ++ int lastSeparator = key.lastIndexOf('.'); ++ if (lastSeparator != -1) { ++ key = key.substring(lastSeparator + 1); ++ } ++ this.configKey = key.toLowerCase(java.util.Locale.ROOT); ++ // Paper end + this.scanRate = senseInterval; + this.timeToTick = (long)RANDOM.nextInt(senseInterval); + } +@@ -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.updateTargetingConditionRanges(entity); ++ // Paper end + this.doTick(world, entity); + } + } diff --git a/patches/server/0557-Add-missing-forceDrop-toggles.patch b/patches/server/0557-Add-missing-forceDrop-toggles.patch new file mode 100644 index 0000000000..aa609aadba --- /dev/null +++ b/patches/server/0557-Add-missing-forceDrop-toggles.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 20 Jul 2021 21:25:35 -0700 +Subject: [PATCH] Add missing forceDrop toggles + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java b/src/main/java/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java +index 4ec1f881c05d96d72814ac3dffd3b4bef40c1bce..c34cb8c918e400636856317cc58356d2677e1d52 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java +@@ -86,7 +86,9 @@ public class WorkAtComposter extends WorkAtPoi { + simpleContainer.removeItemType(Items.WHEAT, m); + ItemStack itemStack = simpleContainer.addItem(new ItemStack(Items.BREAD, l)); + if (!itemStack.isEmpty()) { ++ villager.forceDrops = true; // Paper - Add missing forceDrop toggles + villager.spawnAtLocation(world, itemStack, 0.5F); ++ villager.forceDrops = false; // Paper - Add missing forceDrop toggles + } + } + } +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 705c26ceff9371b09311bd7fa796c0efde7ebfee..4f04170b3ec4ff59358e10ccfd0799af3ab590c3 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java +@@ -540,7 +540,9 @@ public class Panda extends Animal { + + if (world1 instanceof ServerLevel worldserver) { + if (worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { ++ this.forceDrops = true; // Paper - Add missing forceDrop toggles + this.dropFromGiftLootTable(worldserver, BuiltInLootTables.PANDA_SNEEZE, this::spawnAtLocation); ++ this.forceDrops = false; // Paper - Add missing forceDrop toggles + } + } + +@@ -664,7 +666,9 @@ public class Panda extends Animal { + ItemStack itemstack1 = this.getItemBySlot(EquipmentSlot.MAINHAND); + + if (!itemstack1.isEmpty() && !player.hasInfiniteMaterials()) { ++ this.forceDrops = true; // Paper - Add missing forceDrop toggles + this.spawnAtLocation(worldserver, itemstack1); ++ this.forceDrops = false; // Paper - Add missing forceDrop toggles + } + + this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(itemstack.getItem(), 1)); +@@ -942,7 +946,9 @@ public class Panda extends Animal { + ItemStack itemstack = Panda.this.getItemBySlot(EquipmentSlot.MAINHAND); + + if (!itemstack.isEmpty()) { ++ Panda.this.forceDrops = true; // Paper - Add missing forceDrop toggles + Panda.this.spawnAtLocation(getServerLevel(Panda.this.level()), itemstack); ++ Panda.this.forceDrops = false; // Paper - Add missing forceDrop toggles + Panda.this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); + int i = Panda.this.isLazy() ? Panda.this.random.nextInt(50) + 10 : Panda.this.random.nextInt(150) + 10; + +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..be029746905aeba218684b883282649089657de3 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Bogged.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Bogged.java +@@ -145,9 +145,11 @@ public class Bogged extends AbstractSkeleton implements Shearable { + } + + private void spawnShearedMushrooms(ServerLevel world, ItemStack shears) { ++ this.forceDrops = true; // Paper - Add missing forceDrop toggles + this.dropFromShearingLootTable(world, BuiltInLootTables.BOGGED_SHEAR, shears, (worldserver1, itemstack1) -> { + this.spawnAtLocation(worldserver1, itemstack1, this.getBbHeight()); + }); ++ this.forceDrops = false; // Paper - Add missing forceDrop toggles + } + + @Override +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 737c1d5c8ec81d55799ed13560e5e2acc7d8f4e5..5e64a6b94a510ed618a2542ad03e406a181b63d4 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 +@@ -326,9 +326,11 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento + @Override + protected void finishConversion(ServerLevel world) { + PiglinAi.cancelAdmiring(world, this); ++ this.forceDrops = true; // Paper - Add missing forceDrop toggles + this.inventory.removeAllItems().forEach((itemstack) -> { + this.spawnAtLocation(world, itemstack); + }); ++ this.forceDrops = false; // Paper - Add missing forceDrop toggles + super.finishConversion(world); + } + +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 42b1bd58c6e2c3bd1170171eabfefe315202f340..55868c82bf8bd61ce3494aa9f363c20c88ec6aa6 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 +@@ -273,7 +273,9 @@ public class PiglinAi { + + private static void holdInOffhand(ServerLevel world, Piglin piglin, ItemStack stack) { + if (PiglinAi.isHoldingItemInOffHand(piglin)) { ++ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles + piglin.spawnAtLocation(world, piglin.getItemInHand(InteractionHand.OFF_HAND)); ++ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles + } + + piglin.holdInOffHand(stack); +@@ -333,7 +335,9 @@ public class PiglinAi { + + protected static void cancelAdmiring(ServerLevel world, Piglin piglin) { + if (PiglinAi.isAdmiringItem(piglin) && !piglin.getOffhandItem().isEmpty()) { ++ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles + piglin.spawnAtLocation(world, piglin.getOffhandItem()); ++ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles + piglin.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); + } + +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 b6f1d989df3811f423d1cdff98b05ecc4a9268fe..6a7d9b59ff4aa2962a88ae8688c06bc67d70dfda 100644 +--- a/src/main/java/net/minecraft/world/entity/raid/Raider.java ++++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java +@@ -233,7 +233,9 @@ public abstract class Raider extends PatrollingMonster { + double d0 = (double) this.getEquipmentDropChance(enumitemslot); + + if (!itemstack1.isEmpty() && (double) Math.max(this.random.nextFloat() - 0.1F, 0.0F) < d0) { ++ this.forceDrops = true; // Paper - Add missing forceDrop toggles + this.spawnAtLocation(world, itemstack1); ++ this.forceDrops = false; // Paper - Add missing forceDrop toggles + } + + this.onItemPickup(itemEntity); diff --git a/patches/server/0557-Rate-options-and-timings-for-sensors-and-behaviors.patch b/patches/server/0557-Rate-options-and-timings-for-sensors-and-behaviors.patch deleted file mode 100644 index 3473ea4ceb..0000000000 --- a/patches/server/0557-Rate-options-and-timings-for-sensors-and-behaviors.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Phoenix616 -Date: Mon, 28 Jun 2021 22:38:29 +0100 -Subject: [PATCH] Rate options and timings for sensors and behaviors - -This adds config options to specify the tick rate for sensors - and behaviors of different entity types as well as timings - for those in order to be able to have some metrics as to which - ones might need tweaking. - -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..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,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; -+ // Paper end - configurable behavior tick rate and timings - - public Behavior(Map, MemoryStatus> requiredMemoryState) { - this(requiredMemoryState, 60); -@@ -27,6 +30,14 @@ public abstract class Behavior implements BehaviorContro - this.minDuration = minRunTime; - this.maxDuration = maxRunTime; - this.entryCondition = requiredMemoryState; -+ // Paper start - configurable behavior tick rate and timings -+ String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName(); -+ int lastSeparator = key.lastIndexOf('.'); -+ if (lastSeparator != -1) { -+ key = key.substring(lastSeparator + 1); -+ } -+ this.configKey = key.toLowerCase(java.util.Locale.ROOT); -+ // Paper end - configurable behavior tick rate and timings - } - - @Override -@@ -36,6 +47,12 @@ public abstract class Behavior implements BehaviorContro - - @Override - public final boolean tryStart(ServerLevel world, E entity, long time) { -+ // Paper start - configurable behavior tick rate and timings -+ int tickRate = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.behavior.get(entity.getType(), this.configKey), -1); -+ if (tickRate > -1 && time < this.endTimestamp + tickRate) { -+ return false; -+ } -+ // Paper end - configurable behavior tick rate and timings - 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); -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..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,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; -+ // Paper end - - public Sensor(int senseInterval) { -+ // Paper start - configurable sensor tick rate and timings -+ String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName(); -+ int lastSeparator = key.lastIndexOf('.'); -+ if (lastSeparator != -1) { -+ key = key.substring(lastSeparator + 1); -+ } -+ this.configKey = key.toLowerCase(java.util.Locale.ROOT); -+ // Paper end - this.scanRate = senseInterval; - this.timeToTick = (long)RANDOM.nextInt(senseInterval); - } -@@ -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.updateTargetingConditionRanges(entity); -+ // Paper end - this.doTick(world, entity); - } - } diff --git a/patches/server/0558-Add-missing-forceDrop-toggles.patch b/patches/server/0558-Add-missing-forceDrop-toggles.patch deleted file mode 100644 index aa609aadba..0000000000 --- a/patches/server/0558-Add-missing-forceDrop-toggles.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 20 Jul 2021 21:25:35 -0700 -Subject: [PATCH] Add missing forceDrop toggles - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java b/src/main/java/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java -index 4ec1f881c05d96d72814ac3dffd3b4bef40c1bce..c34cb8c918e400636856317cc58356d2677e1d52 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java -@@ -86,7 +86,9 @@ public class WorkAtComposter extends WorkAtPoi { - simpleContainer.removeItemType(Items.WHEAT, m); - ItemStack itemStack = simpleContainer.addItem(new ItemStack(Items.BREAD, l)); - if (!itemStack.isEmpty()) { -+ villager.forceDrops = true; // Paper - Add missing forceDrop toggles - villager.spawnAtLocation(world, itemStack, 0.5F); -+ villager.forceDrops = false; // Paper - Add missing forceDrop toggles - } - } - } -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 705c26ceff9371b09311bd7fa796c0efde7ebfee..4f04170b3ec4ff59358e10ccfd0799af3ab590c3 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Panda.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java -@@ -540,7 +540,9 @@ public class Panda extends Animal { - - if (world1 instanceof ServerLevel worldserver) { - if (worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { -+ this.forceDrops = true; // Paper - Add missing forceDrop toggles - this.dropFromGiftLootTable(worldserver, BuiltInLootTables.PANDA_SNEEZE, this::spawnAtLocation); -+ this.forceDrops = false; // Paper - Add missing forceDrop toggles - } - } - -@@ -664,7 +666,9 @@ public class Panda extends Animal { - ItemStack itemstack1 = this.getItemBySlot(EquipmentSlot.MAINHAND); - - if (!itemstack1.isEmpty() && !player.hasInfiniteMaterials()) { -+ this.forceDrops = true; // Paper - Add missing forceDrop toggles - this.spawnAtLocation(worldserver, itemstack1); -+ this.forceDrops = false; // Paper - Add missing forceDrop toggles - } - - this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(itemstack.getItem(), 1)); -@@ -942,7 +946,9 @@ public class Panda extends Animal { - ItemStack itemstack = Panda.this.getItemBySlot(EquipmentSlot.MAINHAND); - - if (!itemstack.isEmpty()) { -+ Panda.this.forceDrops = true; // Paper - Add missing forceDrop toggles - Panda.this.spawnAtLocation(getServerLevel(Panda.this.level()), itemstack); -+ Panda.this.forceDrops = false; // Paper - Add missing forceDrop toggles - Panda.this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); - int i = Panda.this.isLazy() ? Panda.this.random.nextInt(50) + 10 : Panda.this.random.nextInt(150) + 10; - -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..be029746905aeba218684b883282649089657de3 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Bogged.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Bogged.java -@@ -145,9 +145,11 @@ public class Bogged extends AbstractSkeleton implements Shearable { - } - - private void spawnShearedMushrooms(ServerLevel world, ItemStack shears) { -+ this.forceDrops = true; // Paper - Add missing forceDrop toggles - this.dropFromShearingLootTable(world, BuiltInLootTables.BOGGED_SHEAR, shears, (worldserver1, itemstack1) -> { - this.spawnAtLocation(worldserver1, itemstack1, this.getBbHeight()); - }); -+ this.forceDrops = false; // Paper - Add missing forceDrop toggles - } - - @Override -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 737c1d5c8ec81d55799ed13560e5e2acc7d8f4e5..5e64a6b94a510ed618a2542ad03e406a181b63d4 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 -@@ -326,9 +326,11 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - @Override - protected void finishConversion(ServerLevel world) { - PiglinAi.cancelAdmiring(world, this); -+ this.forceDrops = true; // Paper - Add missing forceDrop toggles - this.inventory.removeAllItems().forEach((itemstack) -> { - this.spawnAtLocation(world, itemstack); - }); -+ this.forceDrops = false; // Paper - Add missing forceDrop toggles - super.finishConversion(world); - } - -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 42b1bd58c6e2c3bd1170171eabfefe315202f340..55868c82bf8bd61ce3494aa9f363c20c88ec6aa6 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 -@@ -273,7 +273,9 @@ public class PiglinAi { - - private static void holdInOffhand(ServerLevel world, Piglin piglin, ItemStack stack) { - if (PiglinAi.isHoldingItemInOffHand(piglin)) { -+ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles - piglin.spawnAtLocation(world, piglin.getItemInHand(InteractionHand.OFF_HAND)); -+ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles - } - - piglin.holdInOffHand(stack); -@@ -333,7 +335,9 @@ public class PiglinAi { - - protected static void cancelAdmiring(ServerLevel world, Piglin piglin) { - if (PiglinAi.isAdmiringItem(piglin) && !piglin.getOffhandItem().isEmpty()) { -+ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles - piglin.spawnAtLocation(world, piglin.getOffhandItem()); -+ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles - piglin.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); - } - -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 b6f1d989df3811f423d1cdff98b05ecc4a9268fe..6a7d9b59ff4aa2962a88ae8688c06bc67d70dfda 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raider.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java -@@ -233,7 +233,9 @@ public abstract class Raider extends PatrollingMonster { - double d0 = (double) this.getEquipmentDropChance(enumitemslot); - - if (!itemstack1.isEmpty() && (double) Math.max(this.random.nextFloat() - 0.1F, 0.0F) < d0) { -+ this.forceDrops = true; // Paper - Add missing forceDrop toggles - this.spawnAtLocation(world, itemstack1); -+ this.forceDrops = false; // Paper - Add missing forceDrop toggles - } - - this.onItemPickup(itemEntity); diff --git a/patches/server/0558-Stinger-API.patch b/patches/server/0558-Stinger-API.patch new file mode 100644 index 0000000000..9e851372d0 --- /dev/null +++ b/patches/server/0558-Stinger-API.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Tue, 22 Jun 2021 23:15:44 -0400 +Subject: [PATCH] Stinger API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 6020c0c164595db4e2001edf0c1fbe99ed87682d..5d6e4f2aeca9be4dd4504bc93b006e89ef875931 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -384,6 +384,39 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + public boolean isInvulnerable() { + return this.getHandle().isInvulnerableTo((ServerLevel) this.getHandle().level(), this.getHandle().damageSources().generic()); + } ++ // Paper start - Bee Stinger API ++ @Override ++ public int getBeeStingerCooldown() { ++ return getHandle().removeStingerTime; ++ } ++ ++ @Override ++ public void setBeeStingerCooldown(int ticks) { ++ getHandle().removeStingerTime = ticks; ++ } ++ ++ @Override ++ public int getBeeStingersInBody() { ++ return getHandle().getStingerCount(); ++ } ++ ++ @Override ++ public void setBeeStingersInBody(int count) { ++ Preconditions.checkArgument(count >= 0, "New bee stinger amount must be >= 0"); ++ getHandle().setStingerCount(count); ++ } ++ ++ @Override ++ public void setNextBeeStingerRemoval(final int ticks) { ++ Preconditions.checkArgument(ticks >= 0, "New amount of ticks before next bee stinger removal must be >= 0"); ++ this.getHandle().removeStingerTime = ticks; ++ } ++ ++ @Override ++ public int getNextBeeStingerRemoval() { ++ return this.getHandle().removeStingerTime; ++ } ++ // Paper end - Bee Stinger API + + @Override + public void damage(double amount) { diff --git a/patches/server/0559-Add-System.out-err-catcher.patch b/patches/server/0559-Add-System.out-err-catcher.patch new file mode 100644 index 0000000000..8b01f8520a --- /dev/null +++ b/patches/server/0559-Add-System.out-err-catcher.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: underscore11code +Date: Fri, 23 Jul 2021 23:01:42 -0700 +Subject: [PATCH] Add System.out/err catcher + + +diff --git a/src/main/java/io/papermc/paper/logging/SysoutCatcher.java b/src/main/java/io/papermc/paper/logging/SysoutCatcher.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a8e813ca89b033f061e695288b3383bdcf128531 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/logging/SysoutCatcher.java +@@ -0,0 +1,94 @@ ++package io.papermc.paper.logging; ++ ++import org.bukkit.Bukkit; ++import org.bukkit.plugin.java.JavaPlugin; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.io.OutputStream; ++import java.io.PrintStream; ++import java.util.Objects; ++import java.util.concurrent.ConcurrentHashMap; ++import java.util.concurrent.ConcurrentMap; ++import java.util.concurrent.TimeUnit; ++import java.util.logging.Level; ++ ++public final class SysoutCatcher { ++ private static final boolean SUPPRESS_NAGS = Boolean.getBoolean("io.papermc.paper.suppress.sout.nags"); ++ // Nanoseconds between nag at most; if interval is caught first, this is reset. ++ // <= 0 for disabling. ++ private static final long NAG_TIMEOUT = TimeUnit.MILLISECONDS.toNanos( ++ Long.getLong("io.papermc.paper.sout.nags.timeout", TimeUnit.MINUTES.toMillis(5L))); ++ // Count since last nag; if timeout is first, this is reset. ++ // <= 0 for disabling. ++ private static final long NAG_INTERVAL = Long.getLong("io.papermc.paper.sout.nags.interval", 200L); ++ ++ // We don't particularly care about how correct this is at any given moment; let's do it on a best attempt basis. ++ // The records are also pretty small, so let's just go for a size of 64 to start... ++ // ++ // Content: Plugin name => nag object ++ // Why plugin name?: This doesn't store a reference to the plugin; keeps the reload ability. ++ // Why not clean on reload?: Effort. ++ private final ConcurrentMap nagRecords = new ConcurrentHashMap<>(64); ++ ++ public SysoutCatcher() { ++ System.setOut(new WrappedOutStream(System.out, Level.INFO, "[STDOUT] ")); ++ System.setErr(new WrappedOutStream(System.err, Level.SEVERE, "[STDERR] ")); ++ } ++ ++ private final class WrappedOutStream extends PrintStream { ++ private static final StackWalker STACK_WALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); ++ private final Level level; ++ private final String prefix; ++ ++ public WrappedOutStream(@NotNull final OutputStream out, final Level level, final String prefix) { ++ super(out); ++ this.level = level; ++ this.prefix = prefix; ++ } ++ ++ @Override ++ public void println(@Nullable final String line) { ++ final Class clazz = STACK_WALKER.getCallerClass(); ++ try { ++ final JavaPlugin plugin = JavaPlugin.getProvidingPlugin(clazz); ++ ++ // Instead of just printing the message, send it to the plugin's logger ++ plugin.getLogger().log(this.level, this.prefix + line); ++ ++ if (SysoutCatcher.SUPPRESS_NAGS) { ++ return; ++ } ++ if (SysoutCatcher.NAG_INTERVAL > 0 || SysoutCatcher.NAG_TIMEOUT > 0) { ++ final PluginNag nagRecord = SysoutCatcher.this.nagRecords.computeIfAbsent(plugin.getName(), k -> new PluginNag()); ++ final boolean hasTimePassed = SysoutCatcher.NAG_TIMEOUT > 0 ++ && (nagRecord.lastNagTimestamp == Long.MIN_VALUE ++ || nagRecord.lastNagTimestamp + SysoutCatcher.NAG_TIMEOUT <= System.nanoTime()); ++ final boolean hasMessagesPassed = SysoutCatcher.NAG_INTERVAL > 0 ++ && (nagRecord.messagesSinceNag == Long.MIN_VALUE ++ || ++nagRecord.messagesSinceNag >= SysoutCatcher.NAG_INTERVAL); ++ if (!hasMessagesPassed && !hasTimePassed) { ++ return; ++ } ++ nagRecord.lastNagTimestamp = System.nanoTime(); ++ nagRecord.messagesSinceNag = 0; ++ } ++ Bukkit.getLogger().warning( ++ String.format("Nag author(s): '%s' of '%s' about their usage of System.out/err.print. " ++ + "Please use your plugin's logger instead (JavaPlugin#getLogger).", ++ plugin.getPluginMeta().getAuthors(), ++ plugin.getPluginMeta().getDisplayName()) ++ ); ++ } catch (final IllegalArgumentException | IllegalStateException e) { ++ // If anything happens, the calling class doesn't exist, there is no JavaPlugin that "owns" the calling class, etc ++ // Just print out normally, with some added information ++ Bukkit.getLogger().log(this.level, String.format("%s[%s] %s", this.prefix, clazz.getName(), line)); ++ } ++ } ++ } ++ ++ private static class PluginNag { ++ private long lastNagTimestamp = Long.MIN_VALUE; ++ private long messagesSinceNag = Long.MIN_VALUE; ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index b4af066a21e4893b5ec146d109b5146b6996a0cf..45d887f4143444321f563cdd7d084b2b9ccf911e 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 { + public Set activeCompatibilities = Collections.emptySet(); + 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 + + static { + ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); diff --git a/patches/server/0559-Stinger-API.patch b/patches/server/0559-Stinger-API.patch deleted file mode 100644 index 9e851372d0..0000000000 --- a/patches/server/0559-Stinger-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: Tue, 22 Jun 2021 23:15:44 -0400 -Subject: [PATCH] Stinger API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 6020c0c164595db4e2001edf0c1fbe99ed87682d..5d6e4f2aeca9be4dd4504bc93b006e89ef875931 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -384,6 +384,39 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - public boolean isInvulnerable() { - return this.getHandle().isInvulnerableTo((ServerLevel) this.getHandle().level(), this.getHandle().damageSources().generic()); - } -+ // Paper start - Bee Stinger API -+ @Override -+ public int getBeeStingerCooldown() { -+ return getHandle().removeStingerTime; -+ } -+ -+ @Override -+ public void setBeeStingerCooldown(int ticks) { -+ getHandle().removeStingerTime = ticks; -+ } -+ -+ @Override -+ public int getBeeStingersInBody() { -+ return getHandle().getStingerCount(); -+ } -+ -+ @Override -+ public void setBeeStingersInBody(int count) { -+ Preconditions.checkArgument(count >= 0, "New bee stinger amount must be >= 0"); -+ getHandle().setStingerCount(count); -+ } -+ -+ @Override -+ public void setNextBeeStingerRemoval(final int ticks) { -+ Preconditions.checkArgument(ticks >= 0, "New amount of ticks before next bee stinger removal must be >= 0"); -+ this.getHandle().removeStingerTime = ticks; -+ } -+ -+ @Override -+ public int getNextBeeStingerRemoval() { -+ return this.getHandle().removeStingerTime; -+ } -+ // Paper end - Bee Stinger API - - @Override - public void damage(double amount) { diff --git a/patches/server/0560-Add-System.out-err-catcher.patch b/patches/server/0560-Add-System.out-err-catcher.patch deleted file mode 100644 index 8b01f8520a..0000000000 --- a/patches/server/0560-Add-System.out-err-catcher.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: underscore11code -Date: Fri, 23 Jul 2021 23:01:42 -0700 -Subject: [PATCH] Add System.out/err catcher - - -diff --git a/src/main/java/io/papermc/paper/logging/SysoutCatcher.java b/src/main/java/io/papermc/paper/logging/SysoutCatcher.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a8e813ca89b033f061e695288b3383bdcf128531 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/logging/SysoutCatcher.java -@@ -0,0 +1,94 @@ -+package io.papermc.paper.logging; -+ -+import org.bukkit.Bukkit; -+import org.bukkit.plugin.java.JavaPlugin; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.io.OutputStream; -+import java.io.PrintStream; -+import java.util.Objects; -+import java.util.concurrent.ConcurrentHashMap; -+import java.util.concurrent.ConcurrentMap; -+import java.util.concurrent.TimeUnit; -+import java.util.logging.Level; -+ -+public final class SysoutCatcher { -+ private static final boolean SUPPRESS_NAGS = Boolean.getBoolean("io.papermc.paper.suppress.sout.nags"); -+ // Nanoseconds between nag at most; if interval is caught first, this is reset. -+ // <= 0 for disabling. -+ private static final long NAG_TIMEOUT = TimeUnit.MILLISECONDS.toNanos( -+ Long.getLong("io.papermc.paper.sout.nags.timeout", TimeUnit.MINUTES.toMillis(5L))); -+ // Count since last nag; if timeout is first, this is reset. -+ // <= 0 for disabling. -+ private static final long NAG_INTERVAL = Long.getLong("io.papermc.paper.sout.nags.interval", 200L); -+ -+ // We don't particularly care about how correct this is at any given moment; let's do it on a best attempt basis. -+ // The records are also pretty small, so let's just go for a size of 64 to start... -+ // -+ // Content: Plugin name => nag object -+ // Why plugin name?: This doesn't store a reference to the plugin; keeps the reload ability. -+ // Why not clean on reload?: Effort. -+ private final ConcurrentMap nagRecords = new ConcurrentHashMap<>(64); -+ -+ public SysoutCatcher() { -+ System.setOut(new WrappedOutStream(System.out, Level.INFO, "[STDOUT] ")); -+ System.setErr(new WrappedOutStream(System.err, Level.SEVERE, "[STDERR] ")); -+ } -+ -+ private final class WrappedOutStream extends PrintStream { -+ private static final StackWalker STACK_WALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); -+ private final Level level; -+ private final String prefix; -+ -+ public WrappedOutStream(@NotNull final OutputStream out, final Level level, final String prefix) { -+ super(out); -+ this.level = level; -+ this.prefix = prefix; -+ } -+ -+ @Override -+ public void println(@Nullable final String line) { -+ final Class clazz = STACK_WALKER.getCallerClass(); -+ try { -+ final JavaPlugin plugin = JavaPlugin.getProvidingPlugin(clazz); -+ -+ // Instead of just printing the message, send it to the plugin's logger -+ plugin.getLogger().log(this.level, this.prefix + line); -+ -+ if (SysoutCatcher.SUPPRESS_NAGS) { -+ return; -+ } -+ if (SysoutCatcher.NAG_INTERVAL > 0 || SysoutCatcher.NAG_TIMEOUT > 0) { -+ final PluginNag nagRecord = SysoutCatcher.this.nagRecords.computeIfAbsent(plugin.getName(), k -> new PluginNag()); -+ final boolean hasTimePassed = SysoutCatcher.NAG_TIMEOUT > 0 -+ && (nagRecord.lastNagTimestamp == Long.MIN_VALUE -+ || nagRecord.lastNagTimestamp + SysoutCatcher.NAG_TIMEOUT <= System.nanoTime()); -+ final boolean hasMessagesPassed = SysoutCatcher.NAG_INTERVAL > 0 -+ && (nagRecord.messagesSinceNag == Long.MIN_VALUE -+ || ++nagRecord.messagesSinceNag >= SysoutCatcher.NAG_INTERVAL); -+ if (!hasMessagesPassed && !hasTimePassed) { -+ return; -+ } -+ nagRecord.lastNagTimestamp = System.nanoTime(); -+ nagRecord.messagesSinceNag = 0; -+ } -+ Bukkit.getLogger().warning( -+ String.format("Nag author(s): '%s' of '%s' about their usage of System.out/err.print. " -+ + "Please use your plugin's logger instead (JavaPlugin#getLogger).", -+ plugin.getPluginMeta().getAuthors(), -+ plugin.getPluginMeta().getDisplayName()) -+ ); -+ } catch (final IllegalArgumentException | IllegalStateException e) { -+ // If anything happens, the calling class doesn't exist, there is no JavaPlugin that "owns" the calling class, etc -+ // Just print out normally, with some added information -+ Bukkit.getLogger().log(this.level, String.format("%s[%s] %s", this.prefix, clazz.getName(), line)); -+ } -+ } -+ } -+ -+ private static class PluginNag { -+ private long lastNagTimestamp = Long.MIN_VALUE; -+ private long messagesSinceNag = Long.MIN_VALUE; -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index b4af066a21e4893b5ec146d109b5146b6996a0cf..45d887f4143444321f563cdd7d084b2b9ccf911e 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 { - public Set activeCompatibilities = Collections.emptySet(); - 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 - - static { - ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); diff --git a/patches/server/0560-Prevent-AFK-kick-while-watching-end-credits.patch b/patches/server/0560-Prevent-AFK-kick-while-watching-end-credits.patch new file mode 100644 index 0000000000..f27fa5d0f8 --- /dev/null +++ b/patches/server/0560-Prevent-AFK-kick-while-watching-end-credits.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Noah van der Aa +Date: Sat, 24 Jul 2021 16:54:11 +0200 +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 fee3bcc109f77b2caaffe95c6bc181457018017d..b9eb462cf7603fb4afe365f6f094c784a5ee1137 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -398,7 +398,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.tabSpamThrottler.tick(); // Paper - configurable tab spam limits + this.recipeSpamPackets.tick(); // Paper - auto recipe limit + this.dropSpamThrottler.tick(); +- if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { ++ if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L && !this.player.wonGame) { // Paper - Prevent AFK kick while watching end credits + this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 + this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause + } diff --git a/patches/server/0561-Allow-skipping-writing-of-comments-to-server.propert.patch b/patches/server/0561-Allow-skipping-writing-of-comments-to-server.propert.patch new file mode 100644 index 0000000000..1fce522892 --- /dev/null +++ b/patches/server/0561-Allow-skipping-writing-of-comments-to-server.propert.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Professor Bloodstone +Date: Fri, 23 Jul 2021 02:32:04 +0200 +Subject: [PATCH] Allow skipping writing of comments to server.properties + +Makes less git noise, as it won't update the date every single time + +Use -DPaper.skipServerPropertiesComments=true flag to disable writing it + +diff --git a/src/main/java/net/minecraft/server/dedicated/Settings.java b/src/main/java/net/minecraft/server/dedicated/Settings.java +index 0ec3b546db0cf3858dd9cd9ea067d1d6713a8491..d7bd235ef2815890e038091dd625177049d253a5 100644 +--- a/src/main/java/net/minecraft/server/dedicated/Settings.java ++++ b/src/main/java/net/minecraft/server/dedicated/Settings.java +@@ -29,6 +29,7 @@ public abstract class Settings> { + + private static final Logger LOGGER = LogUtils.getLogger(); + public final Properties properties; ++ private static final boolean skipComments = Boolean.getBoolean("Paper.skipServerPropertiesComments"); // Paper - allow skipping server.properties comments + // CraftBukkit start + private OptionSet options = null; + +@@ -123,7 +124,46 @@ public abstract class Settings> { + return; + } + // CraftBukkit end +- BufferedWriter bufferedwriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8); ++ // Paper start - allow skipping server.properties comments ++ java.io.OutputStream outputstream = Files.newOutputStream(path); ++ java.io.BufferedOutputStream bufferedOutputStream = !skipComments ? new java.io.BufferedOutputStream(outputstream) : new java.io.BufferedOutputStream(outputstream) { ++ private boolean isRightAfterNewline = true; // If last written char was newline ++ private boolean isComment = false; // Are we writing comment currently? ++ ++ @Override ++ public void write(@org.jetbrains.annotations.NotNull byte[] b) throws IOException { ++ this.write(b, 0, b.length); ++ } ++ ++ @Override ++ public void write(@org.jetbrains.annotations.NotNull byte[] bbuf, int off, int len) throws IOException { ++ int latest_offset = off; // The latest offset, updated when comment ends ++ for (int index = off; index < off + len; ++index ) { ++ byte c = bbuf[index]; ++ boolean isNewline = (c == '\n' || c == '\r'); ++ if (isNewline && this.isComment) { ++ // Comment has ended ++ this.isComment = false; ++ latest_offset = index+1; ++ } ++ if (c == '#' && this.isRightAfterNewline) { ++ this.isComment = true; ++ if (index != latest_offset) { ++ // We got some non-comment data earlier ++ super.write(bbuf, latest_offset, index-latest_offset); ++ } ++ } ++ this.isRightAfterNewline = isNewline; // Store for next iteration ++ ++ } ++ if (latest_offset < off+len && !this.isComment) { ++ // We have some unwritten data, that isn't part of a comment ++ super.write(bbuf, latest_offset, (off + len) - latest_offset); ++ } ++ } ++ }; ++ BufferedWriter bufferedwriter = new BufferedWriter(new java.io.OutputStreamWriter(bufferedOutputStream, java.nio.charset.StandardCharsets.UTF_8.newEncoder())); ++ // Paper end - allow skipping server.properties comments + + try { + this.properties.store(bufferedwriter, "Minecraft server properties"); diff --git a/patches/server/0561-Prevent-AFK-kick-while-watching-end-credits.patch b/patches/server/0561-Prevent-AFK-kick-while-watching-end-credits.patch deleted file mode 100644 index f27fa5d0f8..0000000000 --- a/patches/server/0561-Prevent-AFK-kick-while-watching-end-credits.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Noah van der Aa -Date: Sat, 24 Jul 2021 16:54:11 +0200 -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 fee3bcc109f77b2caaffe95c6bc181457018017d..b9eb462cf7603fb4afe365f6f094c784a5ee1137 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -398,7 +398,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.tabSpamThrottler.tick(); // Paper - configurable tab spam limits - this.recipeSpamPackets.tick(); // Paper - auto recipe limit - this.dropSpamThrottler.tick(); -- if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { -+ if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L && !this.player.wonGame) { // Paper - Prevent AFK kick while watching end credits - this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 - this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause - } diff --git a/patches/server/0562-Add-PlayerSetSpawnEvent.patch b/patches/server/0562-Add-PlayerSetSpawnEvent.patch new file mode 100644 index 0000000000..e86f643009 --- /dev/null +++ b/patches/server/0562-Add-PlayerSetSpawnEvent.patch @@ -0,0 +1,204 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 19 May 2021 18:59:10 -0700 +Subject: [PATCH] Add PlayerSetSpawnEvent + + +diff --git a/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java b/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java +index a2d0699e8427b2262a2396495111125eccafbb66..15db9368227dbc29d07d74e85bd126b345b526b6 100644 +--- a/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java ++++ b/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java +@@ -38,24 +38,34 @@ public class SetSpawnCommand { + ResourceKey resourcekey = source.getLevel().dimension(); + Iterator iterator = targets.iterator(); + ++ final Collection actualTargets = new java.util.ArrayList<>(); // Paper - Add PlayerSetSpawnEvent + while (iterator.hasNext()) { + ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + +- entityplayer.setRespawnPosition(resourcekey, pos, angle, true, false, org.bukkit.event.player.PlayerSpawnChangeEvent.Cause.COMMAND); // CraftBukkit ++ // Paper start - Add PlayerSetSpawnEvent ++ if (entityplayer.setRespawnPosition(resourcekey, pos, angle, true, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.COMMAND)) { ++ actualTargets.add(entityplayer); ++ } ++ // Paper end - Add PlayerSetSpawnEvent + } ++ // Paper start - Add PlayerSetSpawnEvent ++ if (actualTargets.isEmpty()) { ++ return 0; ++ } ++ // Paper end - Add PlayerSetSpawnEvent + + String s = resourcekey.location().toString(); + +- if (targets.size() == 1) { ++ if (actualTargets.size() == 1) { // Paper - Add PlayerSetSpawnEvent + source.sendSuccess(() -> { +- return Component.translatable("commands.spawnpoint.success.single", pos.getX(), pos.getY(), pos.getZ(), angle, s, ((ServerPlayer) targets.iterator().next()).getDisplayName()); ++ return Component.translatable("commands.spawnpoint.success.single", pos.getX(), pos.getY(), pos.getZ(), angle, s, ((ServerPlayer) actualTargets.iterator().next()).getDisplayName()); // Paper - Add PlayerSetSpawnEvent + }, true); + } else { + source.sendSuccess(() -> { +- return Component.translatable("commands.spawnpoint.success.multiple", pos.getX(), pos.getY(), pos.getZ(), angle, s, targets.size()); ++ return Component.translatable("commands.spawnpoint.success.multiple", pos.getX(), pos.getY(), pos.getZ(), angle, s, actualTargets.size()); // Paper - Add PlayerSetSpawnEvent + }, true); + } + +- return targets.size(); ++ return actualTargets.size(); // Paper - Add PlayerSetSpawnEvent + } + } +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index ff678000823fef5f7b04b0023468a17ef1477758..2392b30ef6cc2050be28f6dbd1d922227ab4a490 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1681,7 +1681,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + } else if (this.bedBlocked(blockposition, enumdirection)) { + return Either.left(net.minecraft.world.entity.player.Player.BedSleepingProblem.OBSTRUCTED); + } else { +- this.setRespawnPosition(this.level().dimension(), blockposition, this.getYRot(), false, true, PlayerSpawnChangeEvent.Cause.BED); // CraftBukkit ++ this.setRespawnPosition(this.level().dimension(), blockposition, this.getYRot(), false, true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.BED); // Paper - Add PlayerSetSpawnEvent + if (this.level().isDay()) { + return Either.left(net.minecraft.world.entity.player.Player.BedSleepingProblem.NOT_POSSIBLE_NOW); + } else { +@@ -2617,44 +2617,50 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + this.setRespawnPosition(player.getRespawnDimension(), player.getRespawnPosition(), player.getRespawnAngle(), player.isRespawnForced(), false); + } + ++ @Deprecated // Paper - Add PlayerSetSpawnEvent + public void setRespawnPosition(ResourceKey dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage) { +- // CraftBukkit start +- this.setRespawnPosition(dimension, pos, angle, forced, sendMessage, PlayerSpawnChangeEvent.Cause.UNKNOWN); +- } +- +- public void setRespawnPosition(ResourceKey resourcekey, @Nullable BlockPos blockposition, float f, boolean flag, boolean flag1, PlayerSpawnChangeEvent.Cause cause) { +- ServerLevel newWorld = this.server.getLevel(resourcekey); +- Location newSpawn = (blockposition != null) ? CraftLocation.toBukkit(blockposition, newWorld.getWorld(), f, 0) : null; +- +- PlayerSpawnChangeEvent event = new PlayerSpawnChangeEvent(this.getBukkitEntity(), newSpawn, flag, cause); +- Bukkit.getServer().getPluginManager().callEvent(event); +- if (event.isCancelled()) { +- return; +- } +- newSpawn = event.getNewSpawn(); +- flag = event.isForced(); +- +- if (newSpawn != null) { +- resourcekey = ((CraftWorld) newSpawn.getWorld()).getHandle().dimension(); +- blockposition = BlockPos.containing(newSpawn.getX(), newSpawn.getY(), newSpawn.getZ()); +- f = newSpawn.getYaw(); +- } else { +- resourcekey = Level.OVERWORLD; +- blockposition = null; +- f = 0.0F; ++ // Paper start - Add PlayerSetSpawnEvent ++ this.setRespawnPosition(dimension, pos, angle, forced, sendMessage, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.UNKNOWN); ++ } ++ @Deprecated ++ public boolean setRespawnPosition(ResourceKey dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage, PlayerSpawnChangeEvent.Cause cause) { ++ return this.setRespawnPosition(dimension, pos, angle, forced, sendMessage, cause == PlayerSpawnChangeEvent.Cause.RESET ? ++ com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLAYER_RESPAWN : com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.valueOf(cause.name())); ++ } ++ public boolean setRespawnPosition(ResourceKey dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause cause) { ++ Location spawnLoc = null; ++ boolean willNotify = false; ++ if (pos != null) { ++ boolean flag2 = pos.equals(this.respawnPosition) && dimension.equals(this.respawnDimension); ++ spawnLoc = io.papermc.paper.util.MCUtil.toLocation(this.getServer().getLevel(dimension), pos); ++ spawnLoc.setYaw(angle); ++ willNotify = sendMessage && !flag2; ++ } ++ ++ PlayerSpawnChangeEvent dumbEvent = new PlayerSpawnChangeEvent(this.getBukkitEntity(), spawnLoc, forced, ++ cause == com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLAYER_RESPAWN ? PlayerSpawnChangeEvent.Cause.RESET : PlayerSpawnChangeEvent.Cause.valueOf(cause.name())); ++ dumbEvent.callEvent(); ++ ++ com.destroystokyo.paper.event.player.PlayerSetSpawnEvent event = new com.destroystokyo.paper.event.player.PlayerSetSpawnEvent(this.getBukkitEntity(), cause, dumbEvent.getNewSpawn(), dumbEvent.isForced(), willNotify, willNotify ? net.kyori.adventure.text.Component.translatable("block.minecraft.set_spawn") : null); ++ event.setCancelled(dumbEvent.isCancelled()); ++ if (!event.callEvent()) { ++ return false; + } +- // CraftBukkit end +- if (blockposition != null) { +- boolean flag2 = blockposition.equals(this.respawnPosition) && resourcekey.equals(this.respawnDimension); ++ if (event.getLocation() != null) { ++ dimension = event.getLocation().getWorld() != null ? ((CraftWorld) event.getLocation().getWorld()).getHandle().dimension() : dimension; ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(event.getLocation()); ++ angle = event.getLocation().getYaw(); ++ forced = event.isForced(); ++ // Paper end - Add PlayerSetSpawnEvent + +- if (flag1 && !flag2) { +- this.sendSystemMessage(Component.translatable("block.minecraft.set_spawn")); ++ if (event.willNotifyPlayer() && event.getNotification() != null) { // Paper - Add PlayerSetSpawnEvent ++ this.sendSystemMessage(PaperAdventure.asVanilla(event.getNotification())); // Paper - Add PlayerSetSpawnEvent + } + +- this.respawnPosition = blockposition; +- this.respawnDimension = resourcekey; +- this.respawnAngle = f; +- this.respawnForced = flag; ++ this.respawnPosition = pos; ++ this.respawnDimension = dimension; ++ this.respawnAngle = angle; ++ this.respawnForced = forced; + } else { + this.respawnPosition = null; + this.respawnDimension = Level.OVERWORLD; +@@ -2662,6 +2668,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + this.respawnForced = false; + } + ++ return true; // Paper - Add PlayerSetSpawnEvent + } + + 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 5b6d2080a1e8f8fbc7334071011415b9cb9b4621..9419b073ac2d64d5dad4cefbcb90b4a928ef1dc2 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 { + // CraftBukkit end + if (teleporttransition.missingRespawnBlock()) { + entityplayer1.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F)); +- entityplayer1.setRespawnPosition(null, null, 0f, false, false, PlayerSpawnChangeEvent.Cause.RESET); // CraftBukkit - SPIGOT-5988: Clear respawn location when obstructed ++ entityplayer1.setRespawnPosition(null, null, 0f, false, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLAYER_RESPAWN); // CraftBukkit - SPIGOT-5988: Clear respawn location when obstructed // Paper - PlayerSetSpawnEvent + } + + int i = flag ? 1 : 0; +diff --git a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java +index db26b5a0464bd6087eeacaf6dd61eba37365df92..9117c035d5a6ff114b028fad3380ceb1fc2b9691 100644 +--- a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java +@@ -88,9 +88,14 @@ public class RespawnAnchorBlock extends Block { + ServerPlayer entityplayer = (ServerPlayer) player; + + if (entityplayer.getRespawnDimension() != world.dimension() || !pos.equals(entityplayer.getRespawnPosition())) { +- entityplayer.setRespawnPosition(world.dimension(), pos, 0.0F, false, true, org.bukkit.event.player.PlayerSpawnChangeEvent.Cause.RESPAWN_ANCHOR); // CraftBukkit ++ if (entityplayer.setRespawnPosition(world.dimension(), pos, 0.0F, false, true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.RESPAWN_ANCHOR)) { // Paper - Add PlayerSetSpawnEvent + world.playSound((Player) null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, SoundEvents.RESPAWN_ANCHOR_SET_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F); + return InteractionResult.SUCCESS_SERVER; ++ // Paper start - Add PlayerSetSpawnEvent ++ } else { ++ return InteractionResult.FAIL; ++ } ++ // Paper end - Add PlayerSetSpawnEvent + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index ff8d6a0ceb41258541c0049464dc0923ed4872bd..f363f885b3dc1852b09914f034740794e3025d3d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1420,9 +1420,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + @Override + public void setRespawnLocation(Location location, boolean override) { + if (location == null) { +- this.getHandle().setRespawnPosition(null, null, 0.0F, override, false, PlayerSpawnChangeEvent.Cause.PLUGIN); ++ this.getHandle().setRespawnPosition(null, null, 0.0F, override, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLUGIN); // Paper - Add PlayerSetSpawnEvent + } else { +- this.getHandle().setRespawnPosition(((CraftWorld) location.getWorld()).getHandle().dimension(), CraftLocation.toBlockPosition(location), location.getYaw(), override, false, PlayerSpawnChangeEvent.Cause.PLUGIN); ++ this.getHandle().setRespawnPosition(((CraftWorld) location.getWorld()).getHandle().dimension(), CraftLocation.toBlockPosition(location), location.getYaw(), override, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLUGIN); // Paper - Add PlayerSetSpawnEvent + } + } + diff --git a/patches/server/0562-Allow-skipping-writing-of-comments-to-server.propert.patch b/patches/server/0562-Allow-skipping-writing-of-comments-to-server.propert.patch deleted file mode 100644 index 1fce522892..0000000000 --- a/patches/server/0562-Allow-skipping-writing-of-comments-to-server.propert.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Professor Bloodstone -Date: Fri, 23 Jul 2021 02:32:04 +0200 -Subject: [PATCH] Allow skipping writing of comments to server.properties - -Makes less git noise, as it won't update the date every single time - -Use -DPaper.skipServerPropertiesComments=true flag to disable writing it - -diff --git a/src/main/java/net/minecraft/server/dedicated/Settings.java b/src/main/java/net/minecraft/server/dedicated/Settings.java -index 0ec3b546db0cf3858dd9cd9ea067d1d6713a8491..d7bd235ef2815890e038091dd625177049d253a5 100644 ---- a/src/main/java/net/minecraft/server/dedicated/Settings.java -+++ b/src/main/java/net/minecraft/server/dedicated/Settings.java -@@ -29,6 +29,7 @@ public abstract class Settings> { - - private static final Logger LOGGER = LogUtils.getLogger(); - public final Properties properties; -+ private static final boolean skipComments = Boolean.getBoolean("Paper.skipServerPropertiesComments"); // Paper - allow skipping server.properties comments - // CraftBukkit start - private OptionSet options = null; - -@@ -123,7 +124,46 @@ public abstract class Settings> { - return; - } - // CraftBukkit end -- BufferedWriter bufferedwriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8); -+ // Paper start - allow skipping server.properties comments -+ java.io.OutputStream outputstream = Files.newOutputStream(path); -+ java.io.BufferedOutputStream bufferedOutputStream = !skipComments ? new java.io.BufferedOutputStream(outputstream) : new java.io.BufferedOutputStream(outputstream) { -+ private boolean isRightAfterNewline = true; // If last written char was newline -+ private boolean isComment = false; // Are we writing comment currently? -+ -+ @Override -+ public void write(@org.jetbrains.annotations.NotNull byte[] b) throws IOException { -+ this.write(b, 0, b.length); -+ } -+ -+ @Override -+ public void write(@org.jetbrains.annotations.NotNull byte[] bbuf, int off, int len) throws IOException { -+ int latest_offset = off; // The latest offset, updated when comment ends -+ for (int index = off; index < off + len; ++index ) { -+ byte c = bbuf[index]; -+ boolean isNewline = (c == '\n' || c == '\r'); -+ if (isNewline && this.isComment) { -+ // Comment has ended -+ this.isComment = false; -+ latest_offset = index+1; -+ } -+ if (c == '#' && this.isRightAfterNewline) { -+ this.isComment = true; -+ if (index != latest_offset) { -+ // We got some non-comment data earlier -+ super.write(bbuf, latest_offset, index-latest_offset); -+ } -+ } -+ this.isRightAfterNewline = isNewline; // Store for next iteration -+ -+ } -+ if (latest_offset < off+len && !this.isComment) { -+ // We have some unwritten data, that isn't part of a comment -+ super.write(bbuf, latest_offset, (off + len) - latest_offset); -+ } -+ } -+ }; -+ BufferedWriter bufferedwriter = new BufferedWriter(new java.io.OutputStreamWriter(bufferedOutputStream, java.nio.charset.StandardCharsets.UTF_8.newEncoder())); -+ // Paper end - allow skipping server.properties comments - - try { - this.properties.store(bufferedwriter, "Minecraft server properties"); diff --git a/patches/server/0563-Add-PlayerSetSpawnEvent.patch b/patches/server/0563-Add-PlayerSetSpawnEvent.patch deleted file mode 100644 index bd56b41cb9..0000000000 --- a/patches/server/0563-Add-PlayerSetSpawnEvent.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 19 May 2021 18:59:10 -0700 -Subject: [PATCH] Add PlayerSetSpawnEvent - - -diff --git a/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java b/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java -index a2d0699e8427b2262a2396495111125eccafbb66..15db9368227dbc29d07d74e85bd126b345b526b6 100644 ---- a/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java -+++ b/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java -@@ -38,24 +38,34 @@ public class SetSpawnCommand { - ResourceKey resourcekey = source.getLevel().dimension(); - Iterator iterator = targets.iterator(); - -+ final Collection actualTargets = new java.util.ArrayList<>(); // Paper - Add PlayerSetSpawnEvent - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); - -- entityplayer.setRespawnPosition(resourcekey, pos, angle, true, false, org.bukkit.event.player.PlayerSpawnChangeEvent.Cause.COMMAND); // CraftBukkit -+ // Paper start - Add PlayerSetSpawnEvent -+ if (entityplayer.setRespawnPosition(resourcekey, pos, angle, true, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.COMMAND)) { -+ actualTargets.add(entityplayer); -+ } -+ // Paper end - Add PlayerSetSpawnEvent - } -+ // Paper start - Add PlayerSetSpawnEvent -+ if (actualTargets.isEmpty()) { -+ return 0; -+ } -+ // Paper end - Add PlayerSetSpawnEvent - - String s = resourcekey.location().toString(); - -- if (targets.size() == 1) { -+ if (actualTargets.size() == 1) { // Paper - Add PlayerSetSpawnEvent - source.sendSuccess(() -> { -- return Component.translatable("commands.spawnpoint.success.single", pos.getX(), pos.getY(), pos.getZ(), angle, s, ((ServerPlayer) targets.iterator().next()).getDisplayName()); -+ return Component.translatable("commands.spawnpoint.success.single", pos.getX(), pos.getY(), pos.getZ(), angle, s, ((ServerPlayer) actualTargets.iterator().next()).getDisplayName()); // Paper - Add PlayerSetSpawnEvent - }, true); - } else { - source.sendSuccess(() -> { -- return Component.translatable("commands.spawnpoint.success.multiple", pos.getX(), pos.getY(), pos.getZ(), angle, s, targets.size()); -+ return Component.translatable("commands.spawnpoint.success.multiple", pos.getX(), pos.getY(), pos.getZ(), angle, s, actualTargets.size()); // Paper - Add PlayerSetSpawnEvent - }, true); - } - -- return targets.size(); -+ return actualTargets.size(); // Paper - Add PlayerSetSpawnEvent - } - } -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 4c18d13fdc2221342adb390a6b68be871036c87c..f2cc608d2cf040be2912b604f0d6cab21e33ded0 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1681,7 +1681,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - } else if (this.bedBlocked(blockposition, enumdirection)) { - return Either.left(net.minecraft.world.entity.player.Player.BedSleepingProblem.OBSTRUCTED); - } else { -- this.setRespawnPosition(this.level().dimension(), blockposition, this.getYRot(), false, true, PlayerSpawnChangeEvent.Cause.BED); // CraftBukkit -+ this.setRespawnPosition(this.level().dimension(), blockposition, this.getYRot(), false, true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.BED); // Paper - Add PlayerSetSpawnEvent - if (this.level().isDay()) { - return Either.left(net.minecraft.world.entity.player.Player.BedSleepingProblem.NOT_POSSIBLE_NOW); - } else { -@@ -2617,44 +2617,50 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - this.setRespawnPosition(player.getRespawnDimension(), player.getRespawnPosition(), player.getRespawnAngle(), player.isRespawnForced(), false); - } - -+ @Deprecated // Paper - Add PlayerSetSpawnEvent - public void setRespawnPosition(ResourceKey dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage) { -- // CraftBukkit start -- this.setRespawnPosition(dimension, pos, angle, forced, sendMessage, PlayerSpawnChangeEvent.Cause.UNKNOWN); -- } -- -- public void setRespawnPosition(ResourceKey resourcekey, @Nullable BlockPos blockposition, float f, boolean flag, boolean flag1, PlayerSpawnChangeEvent.Cause cause) { -- ServerLevel newWorld = this.server.getLevel(resourcekey); -- Location newSpawn = (blockposition != null) ? CraftLocation.toBukkit(blockposition, newWorld.getWorld(), f, 0) : null; -- -- PlayerSpawnChangeEvent event = new PlayerSpawnChangeEvent(this.getBukkitEntity(), newSpawn, flag, cause); -- Bukkit.getServer().getPluginManager().callEvent(event); -- if (event.isCancelled()) { -- return; -- } -- newSpawn = event.getNewSpawn(); -- flag = event.isForced(); -- -- if (newSpawn != null) { -- resourcekey = ((CraftWorld) newSpawn.getWorld()).getHandle().dimension(); -- blockposition = BlockPos.containing(newSpawn.getX(), newSpawn.getY(), newSpawn.getZ()); -- f = newSpawn.getYaw(); -- } else { -- resourcekey = Level.OVERWORLD; -- blockposition = null; -- f = 0.0F; -+ // Paper start - Add PlayerSetSpawnEvent -+ this.setRespawnPosition(dimension, pos, angle, forced, sendMessage, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.UNKNOWN); -+ } -+ @Deprecated -+ public boolean setRespawnPosition(ResourceKey dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage, PlayerSpawnChangeEvent.Cause cause) { -+ return this.setRespawnPosition(dimension, pos, angle, forced, sendMessage, cause == PlayerSpawnChangeEvent.Cause.RESET ? -+ com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLAYER_RESPAWN : com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.valueOf(cause.name())); -+ } -+ public boolean setRespawnPosition(ResourceKey dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause cause) { -+ Location spawnLoc = null; -+ boolean willNotify = false; -+ if (pos != null) { -+ boolean flag2 = pos.equals(this.respawnPosition) && dimension.equals(this.respawnDimension); -+ spawnLoc = io.papermc.paper.util.MCUtil.toLocation(this.getServer().getLevel(dimension), pos); -+ spawnLoc.setYaw(angle); -+ willNotify = sendMessage && !flag2; -+ } -+ -+ PlayerSpawnChangeEvent dumbEvent = new PlayerSpawnChangeEvent(this.getBukkitEntity(), spawnLoc, forced, -+ cause == com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLAYER_RESPAWN ? PlayerSpawnChangeEvent.Cause.RESET : PlayerSpawnChangeEvent.Cause.valueOf(cause.name())); -+ dumbEvent.callEvent(); -+ -+ com.destroystokyo.paper.event.player.PlayerSetSpawnEvent event = new com.destroystokyo.paper.event.player.PlayerSetSpawnEvent(this.getBukkitEntity(), cause, dumbEvent.getNewSpawn(), dumbEvent.isForced(), willNotify, willNotify ? net.kyori.adventure.text.Component.translatable("block.minecraft.set_spawn") : null); -+ event.setCancelled(dumbEvent.isCancelled()); -+ if (!event.callEvent()) { -+ return false; - } -- // CraftBukkit end -- if (blockposition != null) { -- boolean flag2 = blockposition.equals(this.respawnPosition) && resourcekey.equals(this.respawnDimension); -+ if (event.getLocation() != null) { -+ dimension = event.getLocation().getWorld() != null ? ((CraftWorld) event.getLocation().getWorld()).getHandle().dimension() : dimension; -+ pos = io.papermc.paper.util.MCUtil.toBlockPosition(event.getLocation()); -+ angle = event.getLocation().getYaw(); -+ forced = event.isForced(); -+ // Paper end - Add PlayerSetSpawnEvent - -- if (flag1 && !flag2) { -- this.sendSystemMessage(Component.translatable("block.minecraft.set_spawn")); -+ if (event.willNotifyPlayer() && event.getNotification() != null) { // Paper - Add PlayerSetSpawnEvent -+ this.sendSystemMessage(PaperAdventure.asVanilla(event.getNotification())); // Paper - Add PlayerSetSpawnEvent - } - -- this.respawnPosition = blockposition; -- this.respawnDimension = resourcekey; -- this.respawnAngle = f; -- this.respawnForced = flag; -+ this.respawnPosition = pos; -+ this.respawnDimension = dimension; -+ this.respawnAngle = angle; -+ this.respawnForced = forced; - } else { - this.respawnPosition = null; - this.respawnDimension = Level.OVERWORLD; -@@ -2662,6 +2668,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - this.respawnForced = false; - } - -+ return true; // Paper - Add PlayerSetSpawnEvent - } - - 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 5b6d2080a1e8f8fbc7334071011415b9cb9b4621..9419b073ac2d64d5dad4cefbcb90b4a928ef1dc2 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 { - // CraftBukkit end - if (teleporttransition.missingRespawnBlock()) { - entityplayer1.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F)); -- entityplayer1.setRespawnPosition(null, null, 0f, false, false, PlayerSpawnChangeEvent.Cause.RESET); // CraftBukkit - SPIGOT-5988: Clear respawn location when obstructed -+ entityplayer1.setRespawnPosition(null, null, 0f, false, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLAYER_RESPAWN); // CraftBukkit - SPIGOT-5988: Clear respawn location when obstructed // Paper - PlayerSetSpawnEvent - } - - int i = flag ? 1 : 0; -diff --git a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java -index db26b5a0464bd6087eeacaf6dd61eba37365df92..9117c035d5a6ff114b028fad3380ceb1fc2b9691 100644 ---- a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java -@@ -88,9 +88,14 @@ public class RespawnAnchorBlock extends Block { - ServerPlayer entityplayer = (ServerPlayer) player; - - if (entityplayer.getRespawnDimension() != world.dimension() || !pos.equals(entityplayer.getRespawnPosition())) { -- entityplayer.setRespawnPosition(world.dimension(), pos, 0.0F, false, true, org.bukkit.event.player.PlayerSpawnChangeEvent.Cause.RESPAWN_ANCHOR); // CraftBukkit -+ if (entityplayer.setRespawnPosition(world.dimension(), pos, 0.0F, false, true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.RESPAWN_ANCHOR)) { // Paper - Add PlayerSetSpawnEvent - world.playSound((Player) null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, SoundEvents.RESPAWN_ANCHOR_SET_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F); - return InteractionResult.SUCCESS_SERVER; -+ // Paper start - Add PlayerSetSpawnEvent -+ } else { -+ return InteractionResult.FAIL; -+ } -+ // Paper end - Add PlayerSetSpawnEvent - } - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index ff8d6a0ceb41258541c0049464dc0923ed4872bd..f363f885b3dc1852b09914f034740794e3025d3d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1420,9 +1420,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - @Override - public void setRespawnLocation(Location location, boolean override) { - if (location == null) { -- this.getHandle().setRespawnPosition(null, null, 0.0F, override, false, PlayerSpawnChangeEvent.Cause.PLUGIN); -+ this.getHandle().setRespawnPosition(null, null, 0.0F, override, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLUGIN); // Paper - Add PlayerSetSpawnEvent - } else { -- this.getHandle().setRespawnPosition(((CraftWorld) location.getWorld()).getHandle().dimension(), CraftLocation.toBlockPosition(location), location.getYaw(), override, false, PlayerSpawnChangeEvent.Cause.PLUGIN); -+ this.getHandle().setRespawnPosition(((CraftWorld) location.getWorld()).getHandle().dimension(), CraftLocation.toBlockPosition(location), location.getYaw(), override, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLUGIN); // Paper - Add PlayerSetSpawnEvent - } - } - diff --git a/patches/server/0563-Make-hoppers-respect-inventory-max-stack-size.patch b/patches/server/0563-Make-hoppers-respect-inventory-max-stack-size.patch new file mode 100644 index 0000000000..fc01c5cad4 --- /dev/null +++ b/patches/server/0563-Make-hoppers-respect-inventory-max-stack-size.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 7 Jul 2021 16:30:17 -0700 +Subject: [PATCH] Make hoppers respect inventory max stack size + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java +index 8913f434967457a16dd708252834ba001ada1a03..b35b44f0776aeb95ef0eda666ba0b652c5e90274 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java +@@ -495,15 +495,17 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + + if (itemstack1.isEmpty()) { + // Spigot start - SPIGOT-6693, InventorySubcontainer#setItem ++ ItemStack leftover = ItemStack.EMPTY; // Paper - Make hoppers respect inventory max stack size + if (!stack.isEmpty() && stack.getCount() > to.getMaxStackSize()) { ++ leftover = stack; // Paper - Make hoppers respect inventory max stack size + stack = stack.split(to.getMaxStackSize()); + } + // Spigot end + to.setItem(slot, stack); +- stack = ItemStack.EMPTY; ++ stack = leftover; // Paper - Make hoppers respect inventory max stack size + flag = true; + } else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) { +- int j = stack.getMaxStackSize() - itemstack1.getCount(); ++ int j = Math.min(stack.getMaxStackSize(), to.getMaxStackSize()) - itemstack1.getCount(); // Paper - Make hoppers respect inventory max stack size + int k = Math.min(stack.getCount(), j); + + stack.shrink(k); diff --git a/patches/server/0564-Make-hoppers-respect-inventory-max-stack-size.patch b/patches/server/0564-Make-hoppers-respect-inventory-max-stack-size.patch deleted file mode 100644 index fc01c5cad4..0000000000 --- a/patches/server/0564-Make-hoppers-respect-inventory-max-stack-size.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 7 Jul 2021 16:30:17 -0700 -Subject: [PATCH] Make hoppers respect inventory max stack size - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index 8913f434967457a16dd708252834ba001ada1a03..b35b44f0776aeb95ef0eda666ba0b652c5e90274 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -@@ -495,15 +495,17 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - if (itemstack1.isEmpty()) { - // Spigot start - SPIGOT-6693, InventorySubcontainer#setItem -+ ItemStack leftover = ItemStack.EMPTY; // Paper - Make hoppers respect inventory max stack size - if (!stack.isEmpty() && stack.getCount() > to.getMaxStackSize()) { -+ leftover = stack; // Paper - Make hoppers respect inventory max stack size - stack = stack.split(to.getMaxStackSize()); - } - // Spigot end - to.setItem(slot, stack); -- stack = ItemStack.EMPTY; -+ stack = leftover; // Paper - Make hoppers respect inventory max stack size - flag = true; - } else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) { -- int j = stack.getMaxStackSize() - itemstack1.getCount(); -+ int j = Math.min(stack.getMaxStackSize(), to.getMaxStackSize()) - itemstack1.getCount(); // Paper - Make hoppers respect inventory max stack size - int k = Math.min(stack.getCount(), j); - - stack.shrink(k); diff --git a/patches/server/0564-Optimize-entity-tracker-passenger-checks.patch b/patches/server/0564-Optimize-entity-tracker-passenger-checks.patch new file mode 100644 index 0000000000..e64be30cfc --- /dev/null +++ b/patches/server/0564-Optimize-entity-tracker-passenger-checks.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Steinborn +Date: Sun, 8 Aug 2021 00:52:54 -0400 +Subject: [PATCH] Optimize entity tracker passenger checks + + +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index 50f1e690d499940ce6c2174dbc609af21fd7b0cb..15968ea0b86a35fec8c0301bbdccc4ecd491197b 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -75,7 +75,7 @@ public class ServerEntity { + private Vec3 lastSentMovement; + private int tickCount; + private int teleportDelay; +- private List lastPassengers = Collections.emptyList(); ++ private List lastPassengers = com.google.common.collect.ImmutableList.of(); // Paper - optimize passenger checks + private boolean wasRiding; + private boolean wasOnGround; + @Nullable diff --git a/patches/server/0565-Config-option-for-Piglins-guarding-chests.patch b/patches/server/0565-Config-option-for-Piglins-guarding-chests.patch new file mode 100644 index 0000000000..32c61a7ec0 --- /dev/null +++ b/patches/server/0565-Config-option-for-Piglins-guarding-chests.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Wed, 2 Dec 2020 03:07:58 -0800 +Subject: [PATCH] Config option for Piglins guarding chests + + +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 55868c82bf8bd61ce3494aa9f363c20c88ec6aa6..4f3048615a34fc2c067e09aec76af94cde6a74e0 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 +@@ -478,6 +478,7 @@ public class PiglinAi { + } + + public static void angerNearbyPiglins(ServerLevel world, Player player, boolean blockOpen) { ++ if (!player.level().paperConfig().entities.behavior.piglinsGuardChests) return; // Paper - Config option for Piglins guarding chests + List list = player.level().getEntitiesOfClass(Piglin.class, player.getBoundingBox().inflate(16.0D)); + + list.stream().filter(PiglinAi::isIdle).filter((entitypiglin) -> { diff --git a/patches/server/0565-Optimize-entity-tracker-passenger-checks.patch b/patches/server/0565-Optimize-entity-tracker-passenger-checks.patch deleted file mode 100644 index e64be30cfc..0000000000 --- a/patches/server/0565-Optimize-entity-tracker-passenger-checks.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrew Steinborn -Date: Sun, 8 Aug 2021 00:52:54 -0400 -Subject: [PATCH] Optimize entity tracker passenger checks - - -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 50f1e690d499940ce6c2174dbc609af21fd7b0cb..15968ea0b86a35fec8c0301bbdccc4ecd491197b 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -75,7 +75,7 @@ public class ServerEntity { - private Vec3 lastSentMovement; - private int tickCount; - private int teleportDelay; -- private List lastPassengers = Collections.emptyList(); -+ private List lastPassengers = com.google.common.collect.ImmutableList.of(); // Paper - optimize passenger checks - private boolean wasRiding; - private boolean wasOnGround; - @Nullable diff --git a/patches/server/0566-Add-EntityDamageItemEvent.patch b/patches/server/0566-Add-EntityDamageItemEvent.patch new file mode 100644 index 0000000000..bfe6c8751a --- /dev/null +++ b/patches/server/0566-Add-EntityDamageItemEvent.patch @@ -0,0 +1,94 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Tue, 22 Dec 2020 13:52:48 -0800 +Subject: [PATCH] Add EntityDamageItemEvent + + +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 225206a055e2f6bf4dbb18434cb3401d02746387..e320264c2283c2c09910ea70606413c73f443b1f 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -697,11 +697,11 @@ public final class ItemStack implements DataComponentHolder { + return this.isDamageableItem() && this.getDamageValue() >= this.getMaxDamage() - 1; + } + +- public void hurtAndBreak(int amount, ServerLevel world, @Nullable ServerPlayer player, Consumer breakCallback) { ++ public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent + int j = this.processDurabilityChange(amount, world, player); + // CraftBukkit start +- if (player != null) { +- PlayerItemDamageEvent event = new PlayerItemDamageEvent(player.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j); ++ if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent ++ PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j); // Paper - Add EntityDamageItemEvent + event.getPlayer().getServer().getPluginManager().callEvent(event); + + if (j != event.getDamage() || event.isCancelled()) { +@@ -712,6 +712,14 @@ public final class ItemStack implements DataComponentHolder { + } + + j = event.getDamage(); ++ // Paper start - Add EntityDamageItemEvent ++ } else if (player != null) { ++ io.papermc.paper.event.entity.EntityDamageItemEvent event = new io.papermc.paper.event.entity.EntityDamageItemEvent(player.getBukkitLivingEntity(), CraftItemStack.asCraftMirror(this), amount); ++ if (!event.callEvent()) { ++ return; ++ } ++ j = event.getDamage(); ++ // Paper end - Add EntityDamageItemEvent + } + // CraftBukkit end + +@@ -721,21 +729,21 @@ public final class ItemStack implements DataComponentHolder { + + } + +- private int processDurabilityChange(int baseDamage, ServerLevel world, @Nullable ServerPlayer player) { +- return !this.isDamageableItem() ? 0 : (player != null && player.hasInfiniteMaterials() ? 0 : (baseDamage > 0 ? EnchantmentHelper.processDurabilityChange(world, this, baseDamage) : baseDamage)); ++ 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 + } + +- private void applyDamage(int damage, @Nullable ServerPlayer player, Consumer breakCallback) { +- if (player != null) { +- CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(player, this, damage); ++ private void applyDamage(int damage, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent ++ if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent ++ CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(serverPlayer, this, damage); // Paper - Add EntityDamageItemEvent + } + + this.setDamageValue(damage); + if (this.isBroken()) { + Item item = this.getItem(); + // CraftBukkit start - Check for item breaking +- if (this.count == 1 && player != null) { +- org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent(player, this); ++ if (this.count == 1 && player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent(serverPlayer, this); // Paper - Add EntityDamageItemEvent + } + // CraftBukkit end + +@@ -773,7 +781,7 @@ public final class ItemStack implements DataComponentHolder { + entityplayer = null; + } + +- this.hurtAndBreak(amount, worldserver, entityplayer, (item) -> { ++ this.hurtAndBreak(amount, worldserver, entity, (item) -> { // Paper - Add EntityDamageItemEvent + entity.onEquippedItemBroken(item, slot); + }); + } +diff --git a/src/main/java/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java b/src/main/java/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java +index 0019c8548aa4901b248ced32cc1475ad14b725bf..7e21c8b10debd70c35a138c14b9b177ef6fff37a 100644 +--- a/src/main/java/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java ++++ b/src/main/java/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java +@@ -21,9 +21,9 @@ public record ChangeItemDamage(LevelBasedValue amount) implements EnchantmentEnt + public void apply(ServerLevel world, int level, EnchantedItemInUse context, Entity user, Vec3 pos) { + ItemStack itemStack = context.itemStack(); + if (itemStack.has(DataComponents.MAX_DAMAGE) && itemStack.has(DataComponents.DAMAGE)) { +- ServerPlayer serverPlayer2 = context.owner() instanceof ServerPlayer serverPlayer ? serverPlayer : null; ++ // ServerPlayer serverPlayer2 = context.owner() instanceof ServerPlayer serverPlayer ? serverPlayer : null; // Paper - EntityDamageItemEvent - always pass in entity + int i = (int)this.amount.calculate(level); +- itemStack.hurtAndBreak(i, world, serverPlayer2, context.onBreak()); ++ itemStack.hurtAndBreak(i, world, context.owner(), context.onBreak()); // Paper - EntityDamageItemEvent - always pass in entity + } + } + diff --git a/patches/server/0566-Config-option-for-Piglins-guarding-chests.patch b/patches/server/0566-Config-option-for-Piglins-guarding-chests.patch deleted file mode 100644 index 32c61a7ec0..0000000000 --- a/patches/server/0566-Config-option-for-Piglins-guarding-chests.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Wed, 2 Dec 2020 03:07:58 -0800 -Subject: [PATCH] Config option for Piglins guarding chests - - -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 55868c82bf8bd61ce3494aa9f363c20c88ec6aa6..4f3048615a34fc2c067e09aec76af94cde6a74e0 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 -@@ -478,6 +478,7 @@ public class PiglinAi { - } - - public static void angerNearbyPiglins(ServerLevel world, Player player, boolean blockOpen) { -+ if (!player.level().paperConfig().entities.behavior.piglinsGuardChests) return; // Paper - Config option for Piglins guarding chests - List list = player.level().getEntitiesOfClass(Piglin.class, player.getBoundingBox().inflate(16.0D)); - - list.stream().filter(PiglinAi::isIdle).filter((entitypiglin) -> { diff --git a/patches/server/0567-Add-EntityDamageItemEvent.patch b/patches/server/0567-Add-EntityDamageItemEvent.patch deleted file mode 100644 index bfe6c8751a..0000000000 --- a/patches/server/0567-Add-EntityDamageItemEvent.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Tue, 22 Dec 2020 13:52:48 -0800 -Subject: [PATCH] Add EntityDamageItemEvent - - -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 225206a055e2f6bf4dbb18434cb3401d02746387..e320264c2283c2c09910ea70606413c73f443b1f 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -697,11 +697,11 @@ public final class ItemStack implements DataComponentHolder { - return this.isDamageableItem() && this.getDamageValue() >= this.getMaxDamage() - 1; - } - -- public void hurtAndBreak(int amount, ServerLevel world, @Nullable ServerPlayer player, Consumer breakCallback) { -+ public void hurtAndBreak(int amount, ServerLevel world, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent - int j = this.processDurabilityChange(amount, world, player); - // CraftBukkit start -- if (player != null) { -- PlayerItemDamageEvent event = new PlayerItemDamageEvent(player.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j); -+ if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent -+ PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), j); // Paper - Add EntityDamageItemEvent - event.getPlayer().getServer().getPluginManager().callEvent(event); - - if (j != event.getDamage() || event.isCancelled()) { -@@ -712,6 +712,14 @@ public final class ItemStack implements DataComponentHolder { - } - - j = event.getDamage(); -+ // Paper start - Add EntityDamageItemEvent -+ } else if (player != null) { -+ io.papermc.paper.event.entity.EntityDamageItemEvent event = new io.papermc.paper.event.entity.EntityDamageItemEvent(player.getBukkitLivingEntity(), CraftItemStack.asCraftMirror(this), amount); -+ if (!event.callEvent()) { -+ return; -+ } -+ j = event.getDamage(); -+ // Paper end - Add EntityDamageItemEvent - } - // CraftBukkit end - -@@ -721,21 +729,21 @@ public final class ItemStack implements DataComponentHolder { - - } - -- private int processDurabilityChange(int baseDamage, ServerLevel world, @Nullable ServerPlayer player) { -- return !this.isDamageableItem() ? 0 : (player != null && player.hasInfiniteMaterials() ? 0 : (baseDamage > 0 ? EnchantmentHelper.processDurabilityChange(world, this, baseDamage) : baseDamage)); -+ 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 - } - -- private void applyDamage(int damage, @Nullable ServerPlayer player, Consumer breakCallback) { -- if (player != null) { -- CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(player, this, damage); -+ private void applyDamage(int damage, @Nullable LivingEntity player, Consumer breakCallback) { // Paper - Add EntityDamageItemEvent -+ if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent -+ CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(serverPlayer, this, damage); // Paper - Add EntityDamageItemEvent - } - - this.setDamageValue(damage); - if (this.isBroken()) { - Item item = this.getItem(); - // CraftBukkit start - Check for item breaking -- if (this.count == 1 && player != null) { -- org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent(player, this); -+ if (this.count == 1 && player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent(serverPlayer, this); // Paper - Add EntityDamageItemEvent - } - // CraftBukkit end - -@@ -773,7 +781,7 @@ public final class ItemStack implements DataComponentHolder { - entityplayer = null; - } - -- this.hurtAndBreak(amount, worldserver, entityplayer, (item) -> { -+ this.hurtAndBreak(amount, worldserver, entity, (item) -> { // Paper - Add EntityDamageItemEvent - entity.onEquippedItemBroken(item, slot); - }); - } -diff --git a/src/main/java/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java b/src/main/java/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java -index 0019c8548aa4901b248ced32cc1475ad14b725bf..7e21c8b10debd70c35a138c14b9b177ef6fff37a 100644 ---- a/src/main/java/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java -+++ b/src/main/java/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java -@@ -21,9 +21,9 @@ public record ChangeItemDamage(LevelBasedValue amount) implements EnchantmentEnt - public void apply(ServerLevel world, int level, EnchantedItemInUse context, Entity user, Vec3 pos) { - ItemStack itemStack = context.itemStack(); - if (itemStack.has(DataComponents.MAX_DAMAGE) && itemStack.has(DataComponents.DAMAGE)) { -- ServerPlayer serverPlayer2 = context.owner() instanceof ServerPlayer serverPlayer ? serverPlayer : null; -+ // ServerPlayer serverPlayer2 = context.owner() instanceof ServerPlayer serverPlayer ? serverPlayer : null; // Paper - EntityDamageItemEvent - always pass in entity - int i = (int)this.amount.calculate(level); -- itemStack.hurtAndBreak(i, world, serverPlayer2, context.onBreak()); -+ itemStack.hurtAndBreak(i, world, context.owner(), context.onBreak()); // Paper - EntityDamageItemEvent - always pass in entity - } - } - diff --git a/patches/server/0567-Optimize-indirect-passenger-iteration.patch b/patches/server/0567-Optimize-indirect-passenger-iteration.patch new file mode 100644 index 0000000000..605e07ec53 --- /dev/null +++ b/patches/server/0567-Optimize-indirect-passenger-iteration.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Steinborn +Date: Mon, 9 Aug 2021 00:38:37 -0400 +Subject: [PATCH] Optimize indirect passenger iteration + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index a3dab1d471e2ac876758d73c7b418a179349a97f..ba1338f25f065a0079e05dd6a20a9cc8b80eef0d 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -4118,20 +4118,34 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + private Stream getIndirectPassengersStream() { ++ if (this.passengers.isEmpty()) { return Stream.of(); } // Paper - Optimize indirect passenger iteration + return this.passengers.stream().flatMap(Entity::getSelfAndPassengers); + } + + @Override + public Stream getSelfAndPassengers() { ++ if (this.passengers.isEmpty()) { return Stream.of(this); } // Paper - Optimize indirect passenger iteration + return Stream.concat(Stream.of(this), this.getIndirectPassengersStream()); + } + + @Override + public Stream getPassengersAndSelf() { ++ if (this.passengers.isEmpty()) { return Stream.of(this); } // Paper - Optimize indirect passenger iteration + return Stream.concat(this.passengers.stream().flatMap(Entity::getPassengersAndSelf), Stream.of(this)); + } + + public Iterable getIndirectPassengers() { ++ // Paper start - Optimize indirect passenger iteration ++ if (this.passengers.isEmpty()) { return ImmutableList.of(); } ++ ImmutableList.Builder indirectPassengers = ImmutableList.builder(); ++ for (Entity passenger : this.passengers) { ++ indirectPassengers.add(passenger); ++ indirectPassengers.addAll(passenger.getIndirectPassengers()); ++ } ++ return indirectPassengers.build(); ++ } ++ private Iterable getIndirectPassengers_old() { ++ // Paper end - Optimize indirect passenger iteration + return () -> { + return this.getIndirectPassengersStream().iterator(); + }; +@@ -4144,6 +4158,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public boolean hasExactlyOnePlayerPassenger() { ++ if (this.passengers.isEmpty()) { return false; } // Paper - Optimize indirect passenger iteration + return this.countPlayerPassengers() == 1; + } + diff --git a/patches/server/0568-Configurable-item-frame-map-cursor-update-interval.patch b/patches/server/0568-Configurable-item-frame-map-cursor-update-interval.patch new file mode 100644 index 0000000000..03aaddc9be --- /dev/null +++ b/patches/server/0568-Configurable-item-frame-map-cursor-update-interval.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Warrior <50800980+Warriorrrr@users.noreply.github.com> +Date: Fri, 13 Aug 2021 01:14:38 +0200 +Subject: [PATCH] Configurable item frame map cursor update interval + + +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index 15968ea0b86a35fec8c0301bbdccc4ecd491197b..78d3aa089d990190cdf5cd7ac14410909235f133 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -120,7 +120,7 @@ public class ServerEntity { + if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block + ItemStack itemstack = entityitemframe.getItem(); + +- if (this.tickCount % 10 == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks ++ 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); + MapItemSavedData worldmap = MapItem.getSavedData(mapid, this.level); + diff --git a/patches/server/0568-Optimize-indirect-passenger-iteration.patch b/patches/server/0568-Optimize-indirect-passenger-iteration.patch deleted file mode 100644 index 40567f5fc9..0000000000 --- a/patches/server/0568-Optimize-indirect-passenger-iteration.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrew Steinborn -Date: Mon, 9 Aug 2021 00:38:37 -0400 -Subject: [PATCH] Optimize indirect passenger iteration - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 627946dba408cea922614497c0c1b2b48a429f06..20f613427d7521456e1a3609a7be2db50da56cd1 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4118,20 +4118,34 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - private Stream getIndirectPassengersStream() { -+ if (this.passengers.isEmpty()) { return Stream.of(); } // Paper - Optimize indirect passenger iteration - return this.passengers.stream().flatMap(Entity::getSelfAndPassengers); - } - - @Override - public Stream getSelfAndPassengers() { -+ if (this.passengers.isEmpty()) { return Stream.of(this); } // Paper - Optimize indirect passenger iteration - return Stream.concat(Stream.of(this), this.getIndirectPassengersStream()); - } - - @Override - public Stream getPassengersAndSelf() { -+ if (this.passengers.isEmpty()) { return Stream.of(this); } // Paper - Optimize indirect passenger iteration - return Stream.concat(this.passengers.stream().flatMap(Entity::getPassengersAndSelf), Stream.of(this)); - } - - public Iterable getIndirectPassengers() { -+ // Paper start - Optimize indirect passenger iteration -+ if (this.passengers.isEmpty()) { return ImmutableList.of(); } -+ ImmutableList.Builder indirectPassengers = ImmutableList.builder(); -+ for (Entity passenger : this.passengers) { -+ indirectPassengers.add(passenger); -+ indirectPassengers.addAll(passenger.getIndirectPassengers()); -+ } -+ return indirectPassengers.build(); -+ } -+ private Iterable getIndirectPassengers_old() { -+ // Paper end - Optimize indirect passenger iteration - return () -> { - return this.getIndirectPassengersStream().iterator(); - }; -@@ -4144,6 +4158,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public boolean hasExactlyOnePlayerPassenger() { -+ if (this.passengers.isEmpty()) { return false; } // Paper - Optimize indirect passenger iteration - return this.countPlayerPassengers() == 1; - } - diff --git a/patches/server/0569-Change-EnderEye-target-without-changing-other-things.patch b/patches/server/0569-Change-EnderEye-target-without-changing-other-things.patch new file mode 100644 index 0000000000..5612422ea7 --- /dev/null +++ b/patches/server/0569-Change-EnderEye-target-without-changing-other-things.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 21 Aug 2021 12:13:53 -0700 +Subject: [PATCH] Change EnderEye target without changing other things + + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EyeOfEnder.java b/src/main/java/net/minecraft/world/entity/projectile/EyeOfEnder.java +index 573b96c9e0c89860c3da031c5aa239f6a7ad0c6e..fd1f5de7dc151dfd187d23e022b2c5435ed8accc 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EyeOfEnder.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EyeOfEnder.java +@@ -76,6 +76,11 @@ public class EyeOfEnder extends Entity implements ItemSupplier { + } + + public void signalTo(BlockPos pos) { ++ // Paper start - Change EnderEye target without changing other things ++ this.signalTo(pos, true); ++ } ++ public void signalTo(BlockPos pos, boolean update) { ++ // Paper end - Change EnderEye target without changing other things + double d0 = (double) pos.getX(); + int i = pos.getY(); + double d1 = (double) pos.getZ(); +@@ -93,8 +98,10 @@ public class EyeOfEnder extends Entity implements ItemSupplier { + this.tz = d1; + } + ++ if (update) { // Paper - Change EnderEye target without changing other things + this.life = 0; + this.surviveAfterDeath = this.random.nextInt(5) > 0; ++ } // Paper - Change EnderEye target without changing other things + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderSignal.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderSignal.java +index d4dfc7a0266086b9bf2c3966c6e149453d0583ba..27f56fa4b7ef92a9a4dfa6b782350424b88210f2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderSignal.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderSignal.java +@@ -32,8 +32,15 @@ public class CraftEnderSignal extends CraftEntity implements EnderSignal { + + @Override + public void setTargetLocation(Location location) { ++ // Paper start - Change EnderEye target without changing other things ++ this.setTargetLocation(location, true); ++ } ++ ++ @Override ++ public void setTargetLocation(Location location, boolean update) { ++ // Paper end - Change EnderEye target without changing other things + Preconditions.checkArgument(this.getWorld().equals(location.getWorld()), "Cannot target EnderSignal across worlds"); +- this.getHandle().signalTo(CraftLocation.toBlockPosition(location)); ++ this.getHandle().signalTo(CraftLocation.toBlockPosition(location), update); // Paper - Change EnderEye target without changing other things + } + + @Override diff --git a/patches/server/0569-Configurable-item-frame-map-cursor-update-interval.patch b/patches/server/0569-Configurable-item-frame-map-cursor-update-interval.patch deleted file mode 100644 index 03aaddc9be..0000000000 --- a/patches/server/0569-Configurable-item-frame-map-cursor-update-interval.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: Fri, 13 Aug 2021 01:14:38 +0200 -Subject: [PATCH] Configurable item frame map cursor update interval - - -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 15968ea0b86a35fec8c0301bbdccc4ecd491197b..78d3aa089d990190cdf5cd7ac14410909235f133 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -120,7 +120,7 @@ public class ServerEntity { - if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block - ItemStack itemstack = entityitemframe.getItem(); - -- if (this.tickCount % 10 == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks -+ 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); - MapItemSavedData worldmap = MapItem.getSavedData(mapid, this.level); - diff --git a/patches/server/0570-Add-BlockBreakBlockEvent.patch b/patches/server/0570-Add-BlockBreakBlockEvent.patch new file mode 100644 index 0000000000..36b29ddf20 --- /dev/null +++ b/patches/server/0570-Add-BlockBreakBlockEvent.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 3 Jan 2021 17:58:11 -0800 +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 533df8ff84ec4224637dfb0837104a6db1ea9901..3c7e373eb1601670d923e6ffa46817ca53e321db 100644 +--- a/src/main/java/net/minecraft/world/level/block/Block.java ++++ b/src/main/java/net/minecraft/world/level/block/Block.java +@@ -295,6 +295,24 @@ public class Block extends BlockBehaviour implements ItemLike { + + } + ++ // Paper start - Add BlockBreakBlockEvent ++ public static boolean dropResources(BlockState state, LevelAccessor levelAccessor, BlockPos pos, @Nullable BlockEntity blockEntity, BlockPos source) { ++ if (levelAccessor instanceof ServerLevel serverLevel) { ++ List items = new java.util.ArrayList<>(); ++ for (ItemStack drop : Block.getDrops(state, serverLevel, pos, blockEntity)) { ++ items.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(drop)); ++ } ++ 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.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); ++ } ++ return true; ++ } ++ // Paper end - Add BlockBreakBlockEvent ++ + public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool) { + if (world instanceof ServerLevel) { + Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> { +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 0c6b517196d48ba4384eac240b7e580adfdbc4d4..4973d75b26880e39d42b5ef533896f43a1f07cba 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 +@@ -406,7 +406,7 @@ public class PistonBaseBlock extends DirectionalBlock { + iblockdata1 = world.getBlockState(blockposition3); + BlockEntity tileentity = iblockdata1.hasBlockEntity() ? world.getBlockEntity(blockposition3) : null; + +- dropResources(iblockdata1, world, blockposition3, tileentity); ++ dropResources(iblockdata1, world, blockposition3, tileentity, pos); // Paper - Add BlockBreakBlockEvent + world.setBlock(blockposition3, Blocks.AIR.defaultBlockState(), 18); + world.gameEvent((Holder) GameEvent.BLOCK_DESTROY, blockposition3, GameEvent.Context.of(iblockdata1)); + if (!iblockdata1.is(BlockTags.FIRE)) { +diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java +index 83dc8bcd9e2b8ecbd32225e4e10aec392ef28325..261e5994d13f8bc30490b86691c80c0a21e7640a 100644 +--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java ++++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java +@@ -316,7 +316,7 @@ public abstract class FlowingFluid extends Fluid { + ifluidcontainer.placeLiquid(world, pos, state, fluidState); + } else { + if (!state.isAir()) { +- this.beforeDestroyingBlock(world, pos, state); ++ this.beforeDestroyingBlock(world, pos, state, pos.relative(direction.getOpposite())); // Paper - Add BlockBreakBlockEvent + } + + world.setBlock(pos, fluidState.createLegacyBlock(), 3); +@@ -324,6 +324,7 @@ public abstract class FlowingFluid extends Fluid { + + } + ++ protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state, BlockPos source) { beforeDestroyingBlock(world, pos, state); } // Paper - Add BlockBreakBlockEvent + protected abstract void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state); + + protected int getSlopeDistance(LevelReader world, BlockPos pos, int i, Direction direction, BlockState state, FlowingFluid.SpreadContext spreadCache) { +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 421f5d9a57d87a87a801213d562ad5fe244e7b65..0a7c05c08bf8c6c331b91e399dc4103a91dc20fe 100644 +--- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java ++++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java +@@ -81,6 +81,13 @@ public abstract class WaterFluid extends FlowingFluid { + return world.getGameRules().getBoolean(GameRules.RULE_WATER_SOURCE_CONVERSION); + } + ++ // Paper start - Add BlockBreakBlockEvent ++ @Override ++ protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state, BlockPos source) { ++ BlockEntity tileentity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null; ++ Block.dropResources(state, world, pos, tileentity, source); ++ } ++ // Paper end - Add BlockBreakBlockEvent + @Override + protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state) { + BlockEntity blockEntity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null; diff --git a/patches/server/0570-Change-EnderEye-target-without-changing-other-things.patch b/patches/server/0570-Change-EnderEye-target-without-changing-other-things.patch deleted file mode 100644 index 5612422ea7..0000000000 --- a/patches/server/0570-Change-EnderEye-target-without-changing-other-things.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 21 Aug 2021 12:13:53 -0700 -Subject: [PATCH] Change EnderEye target without changing other things - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/EyeOfEnder.java b/src/main/java/net/minecraft/world/entity/projectile/EyeOfEnder.java -index 573b96c9e0c89860c3da031c5aa239f6a7ad0c6e..fd1f5de7dc151dfd187d23e022b2c5435ed8accc 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/EyeOfEnder.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/EyeOfEnder.java -@@ -76,6 +76,11 @@ public class EyeOfEnder extends Entity implements ItemSupplier { - } - - public void signalTo(BlockPos pos) { -+ // Paper start - Change EnderEye target without changing other things -+ this.signalTo(pos, true); -+ } -+ public void signalTo(BlockPos pos, boolean update) { -+ // Paper end - Change EnderEye target without changing other things - double d0 = (double) pos.getX(); - int i = pos.getY(); - double d1 = (double) pos.getZ(); -@@ -93,8 +98,10 @@ public class EyeOfEnder extends Entity implements ItemSupplier { - this.tz = d1; - } - -+ if (update) { // Paper - Change EnderEye target without changing other things - this.life = 0; - this.surviveAfterDeath = this.random.nextInt(5) > 0; -+ } // Paper - Change EnderEye target without changing other things - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderSignal.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderSignal.java -index d4dfc7a0266086b9bf2c3966c6e149453d0583ba..27f56fa4b7ef92a9a4dfa6b782350424b88210f2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderSignal.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderSignal.java -@@ -32,8 +32,15 @@ public class CraftEnderSignal extends CraftEntity implements EnderSignal { - - @Override - public void setTargetLocation(Location location) { -+ // Paper start - Change EnderEye target without changing other things -+ this.setTargetLocation(location, true); -+ } -+ -+ @Override -+ public void setTargetLocation(Location location, boolean update) { -+ // Paper end - Change EnderEye target without changing other things - Preconditions.checkArgument(this.getWorld().equals(location.getWorld()), "Cannot target EnderSignal across worlds"); -- this.getHandle().signalTo(CraftLocation.toBlockPosition(location)); -+ this.getHandle().signalTo(CraftLocation.toBlockPosition(location), update); // Paper - Change EnderEye target without changing other things - } - - @Override diff --git a/patches/server/0571-Add-BlockBreakBlockEvent.patch b/patches/server/0571-Add-BlockBreakBlockEvent.patch deleted file mode 100644 index 36b29ddf20..0000000000 --- a/patches/server/0571-Add-BlockBreakBlockEvent.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 3 Jan 2021 17:58:11 -0800 -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 533df8ff84ec4224637dfb0837104a6db1ea9901..3c7e373eb1601670d923e6ffa46817ca53e321db 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -295,6 +295,24 @@ public class Block extends BlockBehaviour implements ItemLike { - - } - -+ // Paper start - Add BlockBreakBlockEvent -+ public static boolean dropResources(BlockState state, LevelAccessor levelAccessor, BlockPos pos, @Nullable BlockEntity blockEntity, BlockPos source) { -+ if (levelAccessor instanceof ServerLevel serverLevel) { -+ List items = new java.util.ArrayList<>(); -+ for (ItemStack drop : Block.getDrops(state, serverLevel, pos, blockEntity)) { -+ items.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(drop)); -+ } -+ 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.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); -+ } -+ return true; -+ } -+ // Paper end - Add BlockBreakBlockEvent -+ - public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool) { - if (world instanceof ServerLevel) { - Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> { -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 0c6b517196d48ba4384eac240b7e580adfdbc4d4..4973d75b26880e39d42b5ef533896f43a1f07cba 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 -@@ -406,7 +406,7 @@ public class PistonBaseBlock extends DirectionalBlock { - iblockdata1 = world.getBlockState(blockposition3); - BlockEntity tileentity = iblockdata1.hasBlockEntity() ? world.getBlockEntity(blockposition3) : null; - -- dropResources(iblockdata1, world, blockposition3, tileentity); -+ dropResources(iblockdata1, world, blockposition3, tileentity, pos); // Paper - Add BlockBreakBlockEvent - world.setBlock(blockposition3, Blocks.AIR.defaultBlockState(), 18); - world.gameEvent((Holder) GameEvent.BLOCK_DESTROY, blockposition3, GameEvent.Context.of(iblockdata1)); - if (!iblockdata1.is(BlockTags.FIRE)) { -diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -index 83dc8bcd9e2b8ecbd32225e4e10aec392ef28325..261e5994d13f8bc30490b86691c80c0a21e7640a 100644 ---- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -@@ -316,7 +316,7 @@ public abstract class FlowingFluid extends Fluid { - ifluidcontainer.placeLiquid(world, pos, state, fluidState); - } else { - if (!state.isAir()) { -- this.beforeDestroyingBlock(world, pos, state); -+ this.beforeDestroyingBlock(world, pos, state, pos.relative(direction.getOpposite())); // Paper - Add BlockBreakBlockEvent - } - - world.setBlock(pos, fluidState.createLegacyBlock(), 3); -@@ -324,6 +324,7 @@ public abstract class FlowingFluid extends Fluid { - - } - -+ protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state, BlockPos source) { beforeDestroyingBlock(world, pos, state); } // Paper - Add BlockBreakBlockEvent - protected abstract void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state); - - protected int getSlopeDistance(LevelReader world, BlockPos pos, int i, Direction direction, BlockState state, FlowingFluid.SpreadContext spreadCache) { -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 421f5d9a57d87a87a801213d562ad5fe244e7b65..0a7c05c08bf8c6c331b91e399dc4103a91dc20fe 100644 ---- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java -@@ -81,6 +81,13 @@ public abstract class WaterFluid extends FlowingFluid { - return world.getGameRules().getBoolean(GameRules.RULE_WATER_SOURCE_CONVERSION); - } - -+ // Paper start - Add BlockBreakBlockEvent -+ @Override -+ protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state, BlockPos source) { -+ BlockEntity tileentity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null; -+ Block.dropResources(state, world, pos, tileentity, source); -+ } -+ // Paper end - Add BlockBreakBlockEvent - @Override - protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state) { - BlockEntity blockEntity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null; diff --git a/patches/server/0571-Option-to-prevent-data-components-copy-in-smithing-r.patch b/patches/server/0571-Option-to-prevent-data-components-copy-in-smithing-r.patch new file mode 100644 index 0000000000..1c9a4f5da5 --- /dev/null +++ b/patches/server/0571-Option-to-prevent-data-components-copy-in-smithing-r.patch @@ -0,0 +1,157 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 26 Sep 2021 12:57:28 -0700 +Subject: [PATCH] Option to prevent data components copy in smithing recipes + + +diff --git a/src/main/java/net/minecraft/world/item/crafting/SmithingTransformRecipe.java b/src/main/java/net/minecraft/world/item/crafting/SmithingTransformRecipe.java +index fa003ce16020eaab554bfd833ace779c8cefc617..017748b26590364d846a5cddaa3490b2293ad276 100644 +--- a/src/main/java/net/minecraft/world/item/crafting/SmithingTransformRecipe.java ++++ b/src/main/java/net/minecraft/world/item/crafting/SmithingTransformRecipe.java +@@ -30,8 +30,15 @@ public class SmithingTransformRecipe implements SmithingRecipe { + final ItemStack result; + @Nullable + private PlacementInfo placementInfo; ++ final boolean copyDataComponents; // Paper - Option to prevent data components copy + + public SmithingTransformRecipe(Optional template, Optional base, Optional addition, ItemStack result) { ++ // Paper start - Option to prevent data components copy ++ this(template, base, addition, result, true); ++ } ++ public SmithingTransformRecipe(Optional template, Optional base, Optional addition, ItemStack result, boolean copyDataComponents) { ++ this.copyDataComponents = copyDataComponents; ++ // Paper end - Option to prevent data components copy + this.template = template; + this.base = base; + this.addition = addition; +@@ -41,7 +48,9 @@ public class SmithingTransformRecipe implements SmithingRecipe { + public ItemStack assemble(SmithingRecipeInput input, HolderLookup.Provider registries) { + ItemStack itemstack = input.base().transmuteCopy(this.result.getItem(), this.result.getCount()); + ++ if (this.copyDataComponents) { // Paper - Option to prevent data components copy + itemstack.applyComponents(this.result.getComponentsPatch()); ++ } // Paper - Option to prevent data components copy + return itemstack; + } + +@@ -84,7 +93,7 @@ public class SmithingTransformRecipe implements SmithingRecipe { + public Recipe toBukkitRecipe(NamespacedKey id) { + CraftItemStack result = CraftItemStack.asCraftMirror(this.result); + +- CraftSmithingTransformRecipe recipe = new CraftSmithingTransformRecipe(id, result, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition)); ++ CraftSmithingTransformRecipe recipe = new CraftSmithingTransformRecipe(id, result, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition), this.copyDataComponents); // Paper - Option to prevent data components copy + + return recipe; + } +diff --git a/src/main/java/net/minecraft/world/item/crafting/SmithingTrimRecipe.java b/src/main/java/net/minecraft/world/item/crafting/SmithingTrimRecipe.java +index a5adce474b2e78233c39cbed367e3d14515923b1..7209170454f10225d7d4a4a107e6717fc18a02ad 100644 +--- a/src/main/java/net/minecraft/world/item/crafting/SmithingTrimRecipe.java ++++ b/src/main/java/net/minecraft/world/item/crafting/SmithingTrimRecipe.java +@@ -35,18 +35,28 @@ public class SmithingTrimRecipe implements SmithingRecipe { + final Optional addition; + @Nullable + private PlacementInfo placementInfo; ++ final boolean copyDataComponents; // Paper - Option to prevent data components copy + + public SmithingTrimRecipe(Optional template, Optional base, Optional addition) { ++ // Paper start - Option to prevent data components copy ++ this(template, base, addition, true); ++ } ++ public SmithingTrimRecipe(Optional template, Optional base, Optional addition, boolean copyDataComponents) { ++ this.copyDataComponents = copyDataComponents; ++ // Paper end - Option to prevent data components copy + this.template = template; + this.base = base; + this.addition = addition; + } + + public ItemStack assemble(SmithingRecipeInput input, HolderLookup.Provider registries) { +- return SmithingTrimRecipe.applyTrim(registries, input.base(), input.addition(), input.template()); ++ return SmithingTrimRecipe.applyTrim(registries, input.base(), input.addition(), input.template(), this.copyDataComponents); + } + + public static ItemStack applyTrim(HolderLookup.Provider registries, ItemStack base, ItemStack addition, ItemStack template) { ++ return applyTrim(registries, base, addition, template, true); ++ } ++ public static ItemStack applyTrim(HolderLookup.Provider registries, ItemStack base, ItemStack addition, ItemStack template, boolean copyDataComponents) { + Optional> optional = TrimMaterials.getFromIngredient(registries, addition); + Optional> optional1 = TrimPatterns.getFromTemplate(registries, template); + +@@ -56,7 +66,7 @@ public class SmithingTrimRecipe implements SmithingRecipe { + if (armortrim != null && armortrim.hasPatternAndMaterial((Holder) optional1.get(), (Holder) optional.get())) { + return ItemStack.EMPTY; + } else { +- ItemStack itemstack3 = base.copyWithCount(1); ++ ItemStack itemstack3 = copyDataComponents ? base.copyWithCount(1) : new ItemStack(base.getItem(), 1); // Paper - Option to prevent data components copy + + itemstack3.set(DataComponents.TRIM, new ArmorTrim((Holder) optional.get(), (Holder) optional1.get())); + return itemstack3; +@@ -107,7 +117,7 @@ public class SmithingTrimRecipe implements SmithingRecipe { + // CraftBukkit start + @Override + public Recipe toBukkitRecipe(NamespacedKey id) { +- return new CraftSmithingTrimRecipe(id, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition)); ++ return new CraftSmithingTrimRecipe(id, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition), this.copyDataComponents); // Paper - Option to prevent data components copy + } + // CraftBukkit end + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java +index 0dc2be8f502a50f13d8fe860c209ebfa43a931ea..af6c1ccdf2b91b1284daee5552eb44cc9a34cd5f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java +@@ -11,12 +11,17 @@ public class CraftSmithingTransformRecipe extends SmithingTransformRecipe implem + public CraftSmithingTransformRecipe(NamespacedKey key, ItemStack result, RecipeChoice template, RecipeChoice base, RecipeChoice addition) { + super(key, result, template, base, addition); + } ++ // Paper start - Option to prevent data components copy ++ public CraftSmithingTransformRecipe(NamespacedKey key, ItemStack result, RecipeChoice template, RecipeChoice base, RecipeChoice addition, boolean copyDataComponents) { ++ super(key, result, template, base, addition, copyDataComponents); ++ } ++ // Paper end - Option to prevent data components copy + + public static CraftSmithingTransformRecipe fromBukkitRecipe(SmithingTransformRecipe recipe) { + if (recipe instanceof CraftSmithingTransformRecipe) { + return (CraftSmithingTransformRecipe) recipe; + } +- CraftSmithingTransformRecipe ret = new CraftSmithingTransformRecipe(recipe.getKey(), recipe.getResult(), recipe.getTemplate(), recipe.getBase(), recipe.getAddition()); ++ CraftSmithingTransformRecipe ret = new CraftSmithingTransformRecipe(recipe.getKey(), recipe.getResult(), recipe.getTemplate(), recipe.getBase(), recipe.getAddition(), recipe.willCopyDataComponents()); // Paper - Option to prevent data components copy + return ret; + } + +@@ -24,6 +29,6 @@ public class CraftSmithingTransformRecipe extends SmithingTransformRecipe implem + public void addToCraftingManager() { + ItemStack result = this.getResult(); + +- MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmithingTransformRecipe(this.toNMSOptional(this.getTemplate(), false), this.toNMSOptional(this.getBase(), false), this.toNMSOptional(this.getAddition(), false), CraftItemStack.asNMSCopy(result)))); ++ MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmithingTransformRecipe(this.toNMSOptional(this.getTemplate(), false), this.toNMSOptional(this.getBase(), false), this.toNMSOptional(this.getAddition(), false), CraftItemStack.asNMSCopy(result), this.willCopyDataComponents()))); // Paper - Option to prevent data components copy + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java +index 202963e2f53b5e7d6fd43c58b27ad49ce009cc3c..fb710aa6dc416a3423345ad5b6e9494507eb0cb4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java +@@ -11,17 +11,22 @@ public class CraftSmithingTrimRecipe extends SmithingTrimRecipe implements Craft + public CraftSmithingTrimRecipe(NamespacedKey key, RecipeChoice template, RecipeChoice base, RecipeChoice addition) { + super(key, template, base, addition); + } ++ // Paper start - Option to prevent data components copy ++ public CraftSmithingTrimRecipe(NamespacedKey key, RecipeChoice template, RecipeChoice base, RecipeChoice addition, boolean copyDataComponents) { ++ super(key, template, base, addition, copyDataComponents); ++ } ++ // Paper end - Option to prevent data components copy + + public static CraftSmithingTrimRecipe fromBukkitRecipe(SmithingTrimRecipe recipe) { + if (recipe instanceof CraftSmithingTrimRecipe) { + return (CraftSmithingTrimRecipe) recipe; + } +- CraftSmithingTrimRecipe ret = new CraftSmithingTrimRecipe(recipe.getKey(), recipe.getTemplate(), recipe.getBase(), recipe.getAddition()); ++ CraftSmithingTrimRecipe ret = new CraftSmithingTrimRecipe(recipe.getKey(), recipe.getTemplate(), recipe.getBase(), recipe.getAddition(), recipe.willCopyDataComponents()); // Paper - Option to prevent data components copy + return ret; + } + + @Override + public void addToCraftingManager() { +- MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmithingTrimRecipe(this.toNMSOptional(this.getTemplate(), false), this.toNMSOptional(this.getBase(), false), this.toNMSOptional(this.getAddition(), false)))); ++ MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmithingTrimRecipe(this.toNMSOptional(this.getTemplate(), false), this.toNMSOptional(this.getBase(), false), this.toNMSOptional(this.getAddition(), false), this.willCopyDataComponents()))); // Paper - Option to prevent data components copy + } + } diff --git a/patches/server/0572-More-CommandBlock-API.patch b/patches/server/0572-More-CommandBlock-API.patch new file mode 100644 index 0000000000..5fa4fa81e1 --- /dev/null +++ b/patches/server/0572-More-CommandBlock-API.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 23 Sep 2021 10:40:09 -0700 +Subject: [PATCH] More CommandBlock API + + +diff --git a/src/main/java/io/papermc/paper/commands/PaperCommandBlockHolder.java b/src/main/java/io/papermc/paper/commands/PaperCommandBlockHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0463aef1c8be238b00e73907bde927f1522a46ce +--- /dev/null ++++ b/src/main/java/io/papermc/paper/commands/PaperCommandBlockHolder.java +@@ -0,0 +1,34 @@ ++package io.papermc.paper.commands; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.command.CommandBlockHolder; ++import net.kyori.adventure.text.Component; ++import net.minecraft.world.level.BaseCommandBlock; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; ++ ++@NullMarked ++public interface PaperCommandBlockHolder extends CommandBlockHolder { ++ ++ BaseCommandBlock getCommandBlockHandle(); ++ ++ @Override ++ default Component lastOutput() { ++ return PaperAdventure.asAdventure(this.getCommandBlockHandle().getLastOutput()); ++ } ++ ++ @Override ++ default void lastOutput(final @Nullable Component lastOutput) { ++ this.getCommandBlockHandle().setLastOutput(PaperAdventure.asVanilla(lastOutput)); ++ } ++ ++ @Override ++ default int getSuccessCount() { ++ return this.getCommandBlockHandle().getSuccessCount(); ++ } ++ ++ @Override ++ default void setSuccessCount(final int successCount) { ++ this.getCommandBlockHandle().setSuccessCount(successCount); ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java +index f5b0bec4c1164fe7ef6da1f19a6ce9bb3d6864d0..138e6539a7786ded482a24aa88a367da7beaabf9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java +@@ -6,7 +6,7 @@ import org.bukkit.World; + import org.bukkit.block.CommandBlock; + import org.bukkit.craftbukkit.util.CraftChatMessage; + +-public class CraftCommandBlock extends CraftBlockEntityState implements CommandBlock { ++public class CraftCommandBlock extends CraftBlockEntityState implements CommandBlock, io.papermc.paper.commands.PaperCommandBlockHolder { + + public CraftCommandBlock(World world, CommandBlockEntity tileEntity) { + super(world, tileEntity); +@@ -56,5 +56,10 @@ public class CraftCommandBlock extends CraftBlockEntityState + public void name(net.kyori.adventure.text.Component name) { + getSnapshot().getCommandBlock().setCustomName(name == null ? net.minecraft.network.chat.Component.literal("@") : io.papermc.paper.adventure.PaperAdventure.asVanilla(name)); + } ++ ++ @Override ++ public net.minecraft.world.level.BaseCommandBlock getCommandBlockHandle() { ++ return getSnapshot().getCommandBlock(); ++ } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartCommand.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartCommand.java +index 9ea1537408ff2d790747b6e5a681d9171a4233ae..f34fa6715e477936097367a7aefd1a2bf87d3d90 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartCommand.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartCommand.java +@@ -13,7 +13,7 @@ import org.bukkit.permissions.PermissionAttachment; + import org.bukkit.permissions.PermissionAttachmentInfo; + import org.bukkit.plugin.Plugin; + +-public class CraftMinecartCommand extends CraftMinecart implements CommandMinecart { ++public class CraftMinecartCommand extends CraftMinecart implements CommandMinecart, io.papermc.paper.commands.PaperCommandBlockHolder { + private final PermissibleBase perm = new PermissibleBase(this); + + public CraftMinecartCommand(CraftServer server, MinecartCommandBlock entity) { +@@ -64,6 +64,17 @@ public class CraftMinecartCommand extends CraftMinecart implements CommandMineca + public net.kyori.adventure.text.@org.jetbrains.annotations.NotNull Component name() { + return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getHandle().getCommandBlock().getName()); + } ++ ++ @Override ++ public net.minecraft.world.level.BaseCommandBlock getCommandBlockHandle() { ++ return getHandle().getCommandBlock(); ++ } ++ ++ @Override ++ public void lastOutput(net.kyori.adventure.text.Component lastOutput) { ++ io.papermc.paper.commands.PaperCommandBlockHolder.super.lastOutput(lastOutput); ++ getCommandBlockHandle().onUpdated(); ++ } + // Paper end + + @Override diff --git a/patches/server/0572-Option-to-prevent-data-components-copy-in-smithing-r.patch b/patches/server/0572-Option-to-prevent-data-components-copy-in-smithing-r.patch deleted file mode 100644 index 1c9a4f5da5..0000000000 --- a/patches/server/0572-Option-to-prevent-data-components-copy-in-smithing-r.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 26 Sep 2021 12:57:28 -0700 -Subject: [PATCH] Option to prevent data components copy in smithing recipes - - -diff --git a/src/main/java/net/minecraft/world/item/crafting/SmithingTransformRecipe.java b/src/main/java/net/minecraft/world/item/crafting/SmithingTransformRecipe.java -index fa003ce16020eaab554bfd833ace779c8cefc617..017748b26590364d846a5cddaa3490b2293ad276 100644 ---- a/src/main/java/net/minecraft/world/item/crafting/SmithingTransformRecipe.java -+++ b/src/main/java/net/minecraft/world/item/crafting/SmithingTransformRecipe.java -@@ -30,8 +30,15 @@ public class SmithingTransformRecipe implements SmithingRecipe { - final ItemStack result; - @Nullable - private PlacementInfo placementInfo; -+ final boolean copyDataComponents; // Paper - Option to prevent data components copy - - public SmithingTransformRecipe(Optional template, Optional base, Optional addition, ItemStack result) { -+ // Paper start - Option to prevent data components copy -+ this(template, base, addition, result, true); -+ } -+ public SmithingTransformRecipe(Optional template, Optional base, Optional addition, ItemStack result, boolean copyDataComponents) { -+ this.copyDataComponents = copyDataComponents; -+ // Paper end - Option to prevent data components copy - this.template = template; - this.base = base; - this.addition = addition; -@@ -41,7 +48,9 @@ public class SmithingTransformRecipe implements SmithingRecipe { - public ItemStack assemble(SmithingRecipeInput input, HolderLookup.Provider registries) { - ItemStack itemstack = input.base().transmuteCopy(this.result.getItem(), this.result.getCount()); - -+ if (this.copyDataComponents) { // Paper - Option to prevent data components copy - itemstack.applyComponents(this.result.getComponentsPatch()); -+ } // Paper - Option to prevent data components copy - return itemstack; - } - -@@ -84,7 +93,7 @@ public class SmithingTransformRecipe implements SmithingRecipe { - public Recipe toBukkitRecipe(NamespacedKey id) { - CraftItemStack result = CraftItemStack.asCraftMirror(this.result); - -- CraftSmithingTransformRecipe recipe = new CraftSmithingTransformRecipe(id, result, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition)); -+ CraftSmithingTransformRecipe recipe = new CraftSmithingTransformRecipe(id, result, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition), this.copyDataComponents); // Paper - Option to prevent data components copy - - return recipe; - } -diff --git a/src/main/java/net/minecraft/world/item/crafting/SmithingTrimRecipe.java b/src/main/java/net/minecraft/world/item/crafting/SmithingTrimRecipe.java -index a5adce474b2e78233c39cbed367e3d14515923b1..7209170454f10225d7d4a4a107e6717fc18a02ad 100644 ---- a/src/main/java/net/minecraft/world/item/crafting/SmithingTrimRecipe.java -+++ b/src/main/java/net/minecraft/world/item/crafting/SmithingTrimRecipe.java -@@ -35,18 +35,28 @@ public class SmithingTrimRecipe implements SmithingRecipe { - final Optional addition; - @Nullable - private PlacementInfo placementInfo; -+ final boolean copyDataComponents; // Paper - Option to prevent data components copy - - public SmithingTrimRecipe(Optional template, Optional base, Optional addition) { -+ // Paper start - Option to prevent data components copy -+ this(template, base, addition, true); -+ } -+ public SmithingTrimRecipe(Optional template, Optional base, Optional addition, boolean copyDataComponents) { -+ this.copyDataComponents = copyDataComponents; -+ // Paper end - Option to prevent data components copy - this.template = template; - this.base = base; - this.addition = addition; - } - - public ItemStack assemble(SmithingRecipeInput input, HolderLookup.Provider registries) { -- return SmithingTrimRecipe.applyTrim(registries, input.base(), input.addition(), input.template()); -+ return SmithingTrimRecipe.applyTrim(registries, input.base(), input.addition(), input.template(), this.copyDataComponents); - } - - public static ItemStack applyTrim(HolderLookup.Provider registries, ItemStack base, ItemStack addition, ItemStack template) { -+ return applyTrim(registries, base, addition, template, true); -+ } -+ public static ItemStack applyTrim(HolderLookup.Provider registries, ItemStack base, ItemStack addition, ItemStack template, boolean copyDataComponents) { - Optional> optional = TrimMaterials.getFromIngredient(registries, addition); - Optional> optional1 = TrimPatterns.getFromTemplate(registries, template); - -@@ -56,7 +66,7 @@ public class SmithingTrimRecipe implements SmithingRecipe { - if (armortrim != null && armortrim.hasPatternAndMaterial((Holder) optional1.get(), (Holder) optional.get())) { - return ItemStack.EMPTY; - } else { -- ItemStack itemstack3 = base.copyWithCount(1); -+ ItemStack itemstack3 = copyDataComponents ? base.copyWithCount(1) : new ItemStack(base.getItem(), 1); // Paper - Option to prevent data components copy - - itemstack3.set(DataComponents.TRIM, new ArmorTrim((Holder) optional.get(), (Holder) optional1.get())); - return itemstack3; -@@ -107,7 +117,7 @@ public class SmithingTrimRecipe implements SmithingRecipe { - // CraftBukkit start - @Override - public Recipe toBukkitRecipe(NamespacedKey id) { -- return new CraftSmithingTrimRecipe(id, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition)); -+ return new CraftSmithingTrimRecipe(id, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition), this.copyDataComponents); // Paper - Option to prevent data components copy - } - // CraftBukkit end - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java -index 0dc2be8f502a50f13d8fe860c209ebfa43a931ea..af6c1ccdf2b91b1284daee5552eb44cc9a34cd5f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java -@@ -11,12 +11,17 @@ public class CraftSmithingTransformRecipe extends SmithingTransformRecipe implem - public CraftSmithingTransformRecipe(NamespacedKey key, ItemStack result, RecipeChoice template, RecipeChoice base, RecipeChoice addition) { - super(key, result, template, base, addition); - } -+ // Paper start - Option to prevent data components copy -+ public CraftSmithingTransformRecipe(NamespacedKey key, ItemStack result, RecipeChoice template, RecipeChoice base, RecipeChoice addition, boolean copyDataComponents) { -+ super(key, result, template, base, addition, copyDataComponents); -+ } -+ // Paper end - Option to prevent data components copy - - public static CraftSmithingTransformRecipe fromBukkitRecipe(SmithingTransformRecipe recipe) { - if (recipe instanceof CraftSmithingTransformRecipe) { - return (CraftSmithingTransformRecipe) recipe; - } -- CraftSmithingTransformRecipe ret = new CraftSmithingTransformRecipe(recipe.getKey(), recipe.getResult(), recipe.getTemplate(), recipe.getBase(), recipe.getAddition()); -+ CraftSmithingTransformRecipe ret = new CraftSmithingTransformRecipe(recipe.getKey(), recipe.getResult(), recipe.getTemplate(), recipe.getBase(), recipe.getAddition(), recipe.willCopyDataComponents()); // Paper - Option to prevent data components copy - return ret; - } - -@@ -24,6 +29,6 @@ public class CraftSmithingTransformRecipe extends SmithingTransformRecipe implem - public void addToCraftingManager() { - ItemStack result = this.getResult(); - -- MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmithingTransformRecipe(this.toNMSOptional(this.getTemplate(), false), this.toNMSOptional(this.getBase(), false), this.toNMSOptional(this.getAddition(), false), CraftItemStack.asNMSCopy(result)))); -+ MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmithingTransformRecipe(this.toNMSOptional(this.getTemplate(), false), this.toNMSOptional(this.getBase(), false), this.toNMSOptional(this.getAddition(), false), CraftItemStack.asNMSCopy(result), this.willCopyDataComponents()))); // Paper - Option to prevent data components copy - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java -index 202963e2f53b5e7d6fd43c58b27ad49ce009cc3c..fb710aa6dc416a3423345ad5b6e9494507eb0cb4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java -@@ -11,17 +11,22 @@ public class CraftSmithingTrimRecipe extends SmithingTrimRecipe implements Craft - public CraftSmithingTrimRecipe(NamespacedKey key, RecipeChoice template, RecipeChoice base, RecipeChoice addition) { - super(key, template, base, addition); - } -+ // Paper start - Option to prevent data components copy -+ public CraftSmithingTrimRecipe(NamespacedKey key, RecipeChoice template, RecipeChoice base, RecipeChoice addition, boolean copyDataComponents) { -+ super(key, template, base, addition, copyDataComponents); -+ } -+ // Paper end - Option to prevent data components copy - - public static CraftSmithingTrimRecipe fromBukkitRecipe(SmithingTrimRecipe recipe) { - if (recipe instanceof CraftSmithingTrimRecipe) { - return (CraftSmithingTrimRecipe) recipe; - } -- CraftSmithingTrimRecipe ret = new CraftSmithingTrimRecipe(recipe.getKey(), recipe.getTemplate(), recipe.getBase(), recipe.getAddition()); -+ CraftSmithingTrimRecipe ret = new CraftSmithingTrimRecipe(recipe.getKey(), recipe.getTemplate(), recipe.getBase(), recipe.getAddition(), recipe.willCopyDataComponents()); // Paper - Option to prevent data components copy - return ret; - } - - @Override - public void addToCraftingManager() { -- MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmithingTrimRecipe(this.toNMSOptional(this.getTemplate(), false), this.toNMSOptional(this.getBase(), false), this.toNMSOptional(this.getAddition(), false)))); -+ MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmithingTrimRecipe(this.toNMSOptional(this.getTemplate(), false), this.toNMSOptional(this.getBase(), false), this.toNMSOptional(this.getAddition(), false), this.willCopyDataComponents()))); // Paper - Option to prevent data components copy - } - } diff --git a/patches/server/0573-Add-missing-team-sidebar-display-slots.patch b/patches/server/0573-Add-missing-team-sidebar-display-slots.patch new file mode 100644 index 0000000000..de7d3fc8e5 --- /dev/null +++ b/patches/server/0573-Add-missing-team-sidebar-display-slots.patch @@ -0,0 +1,114 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 1 Oct 2021 08:04:39 -0700 +Subject: [PATCH] Add missing team sidebar display slots + +== AT == +public org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations +public org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations toBukkitSlot(Lnet/minecraft/world/scores/DisplaySlot;)Lorg/bukkit/scoreboard/DisplaySlot; +public org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations fromBukkitSlot(Lorg/bukkit/scoreboard/DisplaySlot;)Lnet/minecraft/world/scores/DisplaySlot; + +diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java b/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java +index 12fe2f8d0dcb715545e071023490a32125b9c4a4..fe29c08270854d37a4b111f66ebf261260200f28 100644 +--- a/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java ++++ b/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java +@@ -35,6 +35,7 @@ public class FieldRename { + } + + return switch (owner) { ++ case "org/bukkit/scoreboard/DisplaySlot" -> FieldRename.convertDisplaySlot(from); // Paper - DisplaySlot + case "org/bukkit/block/banner/PatternType" -> FieldRename.convertPatternTypeName(apiVersion, from); + case "org/bukkit/enchantments/Enchantment" -> FieldRename.convertEnchantmentName(apiVersion, from); + case "org/bukkit/block/Biome" -> FieldRename.convertBiomeName(apiVersion, from); +@@ -60,6 +61,16 @@ public class FieldRename { + //} + // Paper end + ++ // Paper start - DisplaySlot ++ @DoNotReroute ++ public static String convertDisplaySlot(final String from) { ++ if (from.startsWith("SIDEBAR_") && !from.startsWith("SIDEBAR_TEAM_")) { ++ return from.replace("SIDEBAR_", "SIDEBAR_TEAM_"); ++ } ++ return from; ++ } ++ // Paper end - DisplaySlot ++ + // PatternType + private static final FieldRenameData PATTERN_TYPE_DATA = FieldRenameData.Builder.newBuilder() + .forVersionsBefore(ApiVersion.FIELD_NAME_PARITY) +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java +index 73c5ffff70605b32188a9bb5fb6c0ee04cb66efe..711d227f5ee6d63356a94a0567968da48e9f284c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java +@@ -7,35 +7,22 @@ import org.bukkit.scoreboard.RenderType; + + public final class CraftScoreboardTranslations { + static final int MAX_DISPLAY_SLOT = 19; ++ @Deprecated // Paper + static final ImmutableBiMap SLOTS = ImmutableBiMap.builder() + .put(DisplaySlot.BELOW_NAME, "below_name") + .put(DisplaySlot.PLAYER_LIST, "list") + .put(DisplaySlot.SIDEBAR, "sidebar") +- .put(DisplaySlot.SIDEBAR_BLACK, "sidebar.team.black") +- .put(DisplaySlot.SIDEBAR_DARK_BLUE, "sidebar.team.dark_blue") +- .put(DisplaySlot.SIDEBAR_DARK_GREEN, "sidebar.team.dark_green") +- .put(DisplaySlot.SIDEBAR_DARK_AQUA, "sidebar.team.dark_aqua") +- .put(DisplaySlot.SIDEBAR_DARK_RED, "sidebar.team.dark_red") +- .put(DisplaySlot.SIDEBAR_DARK_PURPLE, "sidebar.team.dark_purple") +- .put(DisplaySlot.SIDEBAR_GOLD, "sidebar.team.gold") +- .put(DisplaySlot.SIDEBAR_GRAY, "sidebar.team.gray") +- .put(DisplaySlot.SIDEBAR_DARK_GRAY, "sidebar.team.dark_gray") +- .put(DisplaySlot.SIDEBAR_BLUE, "sidebar.team.blue") +- .put(DisplaySlot.SIDEBAR_GREEN, "sidebar.team.green") +- .put(DisplaySlot.SIDEBAR_AQUA, "sidebar.team.aqua") +- .put(DisplaySlot.SIDEBAR_RED, "sidebar.team.red") +- .put(DisplaySlot.SIDEBAR_LIGHT_PURPLE, "sidebar.team.light_purple") +- .put(DisplaySlot.SIDEBAR_YELLOW, "sidebar.team.yellow") +- .put(DisplaySlot.SIDEBAR_WHITE, "sidebar.team.white") + .buildOrThrow(); + + private CraftScoreboardTranslations() {} + + public static DisplaySlot toBukkitSlot(net.minecraft.world.scores.DisplaySlot minecraft) { ++ if (true) return DisplaySlot.NAMES.value(minecraft.getSerializedName()); // Paper + return CraftScoreboardTranslations.SLOTS.inverse().get(minecraft.getSerializedName()); + } + + public static net.minecraft.world.scores.DisplaySlot fromBukkitSlot(DisplaySlot slot) { ++ if (true) return net.minecraft.world.scores.DisplaySlot.CODEC.byName(slot.getId()); // Paper + return net.minecraft.world.scores.DisplaySlot.CODEC.byName(CraftScoreboardTranslations.SLOTS.get(slot)); + } + +diff --git a/src/test/java/io/papermc/paper/scoreboard/DisplaySlotTest.java b/src/test/java/io/papermc/paper/scoreboard/DisplaySlotTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..345c96bfb6c559b41c2b6682067198a74d35b440 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/scoreboard/DisplaySlotTest.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.scoreboard; ++ ++import org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations; ++import org.bukkit.scoreboard.DisplaySlot; ++import org.bukkit.support.environment.Normal; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertNotNull; ++ ++@Normal ++public class DisplaySlotTest { ++ ++ @Test ++ public void testBukkitToMinecraftDisplaySlots() { ++ for (DisplaySlot bukkitSlot : DisplaySlot.values()) { ++ assertNotNull(CraftScoreboardTranslations.fromBukkitSlot(bukkitSlot)); ++ } ++ } ++ ++ @Test ++ public void testMinecraftToBukkitDisplaySlots() { ++ for (net.minecraft.world.scores.DisplaySlot nmsSlot : net.minecraft.world.scores.DisplaySlot.values()) { ++ assertNotNull(CraftScoreboardTranslations.toBukkitSlot(nmsSlot)); ++ } ++ } ++} diff --git a/patches/server/0573-More-CommandBlock-API.patch b/patches/server/0573-More-CommandBlock-API.patch deleted file mode 100644 index 5fa4fa81e1..0000000000 --- a/patches/server/0573-More-CommandBlock-API.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 23 Sep 2021 10:40:09 -0700 -Subject: [PATCH] More CommandBlock API - - -diff --git a/src/main/java/io/papermc/paper/commands/PaperCommandBlockHolder.java b/src/main/java/io/papermc/paper/commands/PaperCommandBlockHolder.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0463aef1c8be238b00e73907bde927f1522a46ce ---- /dev/null -+++ b/src/main/java/io/papermc/paper/commands/PaperCommandBlockHolder.java -@@ -0,0 +1,34 @@ -+package io.papermc.paper.commands; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import io.papermc.paper.command.CommandBlockHolder; -+import net.kyori.adventure.text.Component; -+import net.minecraft.world.level.BaseCommandBlock; -+import org.jspecify.annotations.NullMarked; -+import org.jspecify.annotations.Nullable; -+ -+@NullMarked -+public interface PaperCommandBlockHolder extends CommandBlockHolder { -+ -+ BaseCommandBlock getCommandBlockHandle(); -+ -+ @Override -+ default Component lastOutput() { -+ return PaperAdventure.asAdventure(this.getCommandBlockHandle().getLastOutput()); -+ } -+ -+ @Override -+ default void lastOutput(final @Nullable Component lastOutput) { -+ this.getCommandBlockHandle().setLastOutput(PaperAdventure.asVanilla(lastOutput)); -+ } -+ -+ @Override -+ default int getSuccessCount() { -+ return this.getCommandBlockHandle().getSuccessCount(); -+ } -+ -+ @Override -+ default void setSuccessCount(final int successCount) { -+ this.getCommandBlockHandle().setSuccessCount(successCount); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java -index f5b0bec4c1164fe7ef6da1f19a6ce9bb3d6864d0..138e6539a7786ded482a24aa88a367da7beaabf9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java -@@ -6,7 +6,7 @@ import org.bukkit.World; - import org.bukkit.block.CommandBlock; - import org.bukkit.craftbukkit.util.CraftChatMessage; - --public class CraftCommandBlock extends CraftBlockEntityState implements CommandBlock { -+public class CraftCommandBlock extends CraftBlockEntityState implements CommandBlock, io.papermc.paper.commands.PaperCommandBlockHolder { - - public CraftCommandBlock(World world, CommandBlockEntity tileEntity) { - super(world, tileEntity); -@@ -56,5 +56,10 @@ public class CraftCommandBlock extends CraftBlockEntityState - public void name(net.kyori.adventure.text.Component name) { - getSnapshot().getCommandBlock().setCustomName(name == null ? net.minecraft.network.chat.Component.literal("@") : io.papermc.paper.adventure.PaperAdventure.asVanilla(name)); - } -+ -+ @Override -+ public net.minecraft.world.level.BaseCommandBlock getCommandBlockHandle() { -+ return getSnapshot().getCommandBlock(); -+ } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartCommand.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartCommand.java -index 9ea1537408ff2d790747b6e5a681d9171a4233ae..f34fa6715e477936097367a7aefd1a2bf87d3d90 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartCommand.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartCommand.java -@@ -13,7 +13,7 @@ import org.bukkit.permissions.PermissionAttachment; - import org.bukkit.permissions.PermissionAttachmentInfo; - import org.bukkit.plugin.Plugin; - --public class CraftMinecartCommand extends CraftMinecart implements CommandMinecart { -+public class CraftMinecartCommand extends CraftMinecart implements CommandMinecart, io.papermc.paper.commands.PaperCommandBlockHolder { - private final PermissibleBase perm = new PermissibleBase(this); - - public CraftMinecartCommand(CraftServer server, MinecartCommandBlock entity) { -@@ -64,6 +64,17 @@ public class CraftMinecartCommand extends CraftMinecart implements CommandMineca - public net.kyori.adventure.text.@org.jetbrains.annotations.NotNull Component name() { - return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getHandle().getCommandBlock().getName()); - } -+ -+ @Override -+ public net.minecraft.world.level.BaseCommandBlock getCommandBlockHandle() { -+ return getHandle().getCommandBlock(); -+ } -+ -+ @Override -+ public void lastOutput(net.kyori.adventure.text.Component lastOutput) { -+ io.papermc.paper.commands.PaperCommandBlockHolder.super.lastOutput(lastOutput); -+ getCommandBlockHandle().onUpdated(); -+ } - // Paper end - - @Override diff --git a/patches/server/0574-Add-back-EntityPortalExitEvent.patch b/patches/server/0574-Add-back-EntityPortalExitEvent.patch new file mode 100644 index 0000000000..84893e4fc4 --- /dev/null +++ b/patches/server/0574-Add-back-EntityPortalExitEvent.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 16 May 2021 09:39:46 -0700 +Subject: [PATCH] Add back EntityPortalExitEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index ba1338f25f065a0079e05dd6a20a9cc8b80eef0d..2a9be5b06f2f9db8f1ed2061c4fc3f94600e266a 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3522,6 +3522,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + if (!this.isRemoved()) { + // CraftBukkit start + PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTarget), teleportTarget.relatives()); ++ Vec3 velocity = absolutePosition.deltaMovement(); // Paper + Location to = CraftLocation.toBukkit(absolutePosition.position(), teleportTarget.newLevel().getWorld(), absolutePosition.yRot(), absolutePosition.xRot()); + // Paper start - gateway-specific teleport event + final EntityTeleportEvent teleEvent; +@@ -3538,7 +3539,29 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + if (!to.equals(teleEvent.getTo())) { + to = teleEvent.getTo(); + teleportTarget = new TeleportTransition(((CraftWorld) to.getWorld()).getHandle(), CraftLocation.toVec3D(to), Vec3.ZERO, to.getYaw(), to.getPitch(), teleportTarget.missingRespawnBlock(), teleportTarget.asPassenger(), Set.of(), teleportTarget.postTeleportTransition(), teleportTarget.cause()); ++ // Paper start - Call EntityPortalExitEvent ++ velocity = Vec3.ZERO; + } ++ if (this.portalProcess != null) { // if in a portal ++ CraftEntity bukkitEntity = this.getBukkitEntity(); ++ org.bukkit.event.entity.EntityPortalExitEvent event = new org.bukkit.event.entity.EntityPortalExitEvent( ++ bukkitEntity, ++ bukkitEntity.getLocation(), to.clone(), ++ bukkitEntity.getVelocity(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(velocity) ++ ); ++ event.callEvent(); ++ ++ // Only change the target if actually needed, since we reset relative flags ++ if (!event.isCancelled() && event.getTo() != null && (!event.getTo().equals(event.getFrom()) || !event.getAfter().equals(event.getBefore()))) { ++ to = event.getTo().clone(); ++ velocity = org.bukkit.craftbukkit.util.CraftVector.toNMS(event.getAfter()); ++ teleportTarget = new TeleportTransition(((CraftWorld) to.getWorld()).getHandle(), CraftLocation.toVec3D(to), velocity, to.getYaw(), to.getPitch(), teleportTarget.missingRespawnBlock(), teleportTarget.asPassenger(), Set.of(), teleportTarget.postTeleportTransition(), teleportTarget.cause()); ++ } ++ } ++ if (this.isRemoved()) { ++ return null; ++ } ++ // Paper end - Call EntityPortalExitEvent + // CraftBukkit end + ServerLevel worldserver1 = teleportTarget.newLevel(); + boolean flag = worldserver1.dimension() != worldserver.dimension(); diff --git a/patches/server/0574-Add-missing-team-sidebar-display-slots.patch b/patches/server/0574-Add-missing-team-sidebar-display-slots.patch deleted file mode 100644 index de7d3fc8e5..0000000000 --- a/patches/server/0574-Add-missing-team-sidebar-display-slots.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 1 Oct 2021 08:04:39 -0700 -Subject: [PATCH] Add missing team sidebar display slots - -== AT == -public org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations -public org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations toBukkitSlot(Lnet/minecraft/world/scores/DisplaySlot;)Lorg/bukkit/scoreboard/DisplaySlot; -public org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations fromBukkitSlot(Lorg/bukkit/scoreboard/DisplaySlot;)Lnet/minecraft/world/scores/DisplaySlot; - -diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java b/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java -index 12fe2f8d0dcb715545e071023490a32125b9c4a4..fe29c08270854d37a4b111f66ebf261260200f28 100644 ---- a/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java -+++ b/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java -@@ -35,6 +35,7 @@ public class FieldRename { - } - - return switch (owner) { -+ case "org/bukkit/scoreboard/DisplaySlot" -> FieldRename.convertDisplaySlot(from); // Paper - DisplaySlot - case "org/bukkit/block/banner/PatternType" -> FieldRename.convertPatternTypeName(apiVersion, from); - case "org/bukkit/enchantments/Enchantment" -> FieldRename.convertEnchantmentName(apiVersion, from); - case "org/bukkit/block/Biome" -> FieldRename.convertBiomeName(apiVersion, from); -@@ -60,6 +61,16 @@ public class FieldRename { - //} - // Paper end - -+ // Paper start - DisplaySlot -+ @DoNotReroute -+ public static String convertDisplaySlot(final String from) { -+ if (from.startsWith("SIDEBAR_") && !from.startsWith("SIDEBAR_TEAM_")) { -+ return from.replace("SIDEBAR_", "SIDEBAR_TEAM_"); -+ } -+ return from; -+ } -+ // Paper end - DisplaySlot -+ - // PatternType - private static final FieldRenameData PATTERN_TYPE_DATA = FieldRenameData.Builder.newBuilder() - .forVersionsBefore(ApiVersion.FIELD_NAME_PARITY) -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java -index 73c5ffff70605b32188a9bb5fb6c0ee04cb66efe..711d227f5ee6d63356a94a0567968da48e9f284c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardTranslations.java -@@ -7,35 +7,22 @@ import org.bukkit.scoreboard.RenderType; - - public final class CraftScoreboardTranslations { - static final int MAX_DISPLAY_SLOT = 19; -+ @Deprecated // Paper - static final ImmutableBiMap SLOTS = ImmutableBiMap.builder() - .put(DisplaySlot.BELOW_NAME, "below_name") - .put(DisplaySlot.PLAYER_LIST, "list") - .put(DisplaySlot.SIDEBAR, "sidebar") -- .put(DisplaySlot.SIDEBAR_BLACK, "sidebar.team.black") -- .put(DisplaySlot.SIDEBAR_DARK_BLUE, "sidebar.team.dark_blue") -- .put(DisplaySlot.SIDEBAR_DARK_GREEN, "sidebar.team.dark_green") -- .put(DisplaySlot.SIDEBAR_DARK_AQUA, "sidebar.team.dark_aqua") -- .put(DisplaySlot.SIDEBAR_DARK_RED, "sidebar.team.dark_red") -- .put(DisplaySlot.SIDEBAR_DARK_PURPLE, "sidebar.team.dark_purple") -- .put(DisplaySlot.SIDEBAR_GOLD, "sidebar.team.gold") -- .put(DisplaySlot.SIDEBAR_GRAY, "sidebar.team.gray") -- .put(DisplaySlot.SIDEBAR_DARK_GRAY, "sidebar.team.dark_gray") -- .put(DisplaySlot.SIDEBAR_BLUE, "sidebar.team.blue") -- .put(DisplaySlot.SIDEBAR_GREEN, "sidebar.team.green") -- .put(DisplaySlot.SIDEBAR_AQUA, "sidebar.team.aqua") -- .put(DisplaySlot.SIDEBAR_RED, "sidebar.team.red") -- .put(DisplaySlot.SIDEBAR_LIGHT_PURPLE, "sidebar.team.light_purple") -- .put(DisplaySlot.SIDEBAR_YELLOW, "sidebar.team.yellow") -- .put(DisplaySlot.SIDEBAR_WHITE, "sidebar.team.white") - .buildOrThrow(); - - private CraftScoreboardTranslations() {} - - public static DisplaySlot toBukkitSlot(net.minecraft.world.scores.DisplaySlot minecraft) { -+ if (true) return DisplaySlot.NAMES.value(minecraft.getSerializedName()); // Paper - return CraftScoreboardTranslations.SLOTS.inverse().get(minecraft.getSerializedName()); - } - - public static net.minecraft.world.scores.DisplaySlot fromBukkitSlot(DisplaySlot slot) { -+ if (true) return net.minecraft.world.scores.DisplaySlot.CODEC.byName(slot.getId()); // Paper - return net.minecraft.world.scores.DisplaySlot.CODEC.byName(CraftScoreboardTranslations.SLOTS.get(slot)); - } - -diff --git a/src/test/java/io/papermc/paper/scoreboard/DisplaySlotTest.java b/src/test/java/io/papermc/paper/scoreboard/DisplaySlotTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..345c96bfb6c559b41c2b6682067198a74d35b440 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/scoreboard/DisplaySlotTest.java -@@ -0,0 +1,26 @@ -+package io.papermc.paper.scoreboard; -+ -+import org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations; -+import org.bukkit.scoreboard.DisplaySlot; -+import org.bukkit.support.environment.Normal; -+import org.junit.jupiter.api.Test; -+ -+import static org.junit.jupiter.api.Assertions.assertNotNull; -+ -+@Normal -+public class DisplaySlotTest { -+ -+ @Test -+ public void testBukkitToMinecraftDisplaySlots() { -+ for (DisplaySlot bukkitSlot : DisplaySlot.values()) { -+ assertNotNull(CraftScoreboardTranslations.fromBukkitSlot(bukkitSlot)); -+ } -+ } -+ -+ @Test -+ public void testMinecraftToBukkitDisplaySlots() { -+ for (net.minecraft.world.scores.DisplaySlot nmsSlot : net.minecraft.world.scores.DisplaySlot.values()) { -+ assertNotNull(CraftScoreboardTranslations.toBukkitSlot(nmsSlot)); -+ } -+ } -+} diff --git a/patches/server/0575-Add-back-EntityPortalExitEvent.patch b/patches/server/0575-Add-back-EntityPortalExitEvent.patch deleted file mode 100644 index cda1504b0b..0000000000 --- a/patches/server/0575-Add-back-EntityPortalExitEvent.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 16 May 2021 09:39:46 -0700 -Subject: [PATCH] Add back EntityPortalExitEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 20f613427d7521456e1a3609a7be2db50da56cd1..dbea0da4b2c0dda744a1995c779049d3d63351cb 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3522,6 +3522,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (!this.isRemoved()) { - // CraftBukkit start - PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTarget), teleportTarget.relatives()); -+ Vec3 velocity = absolutePosition.deltaMovement(); // Paper - Location to = CraftLocation.toBukkit(absolutePosition.position(), teleportTarget.newLevel().getWorld(), absolutePosition.yRot(), absolutePosition.xRot()); - // Paper start - gateway-specific teleport event - final EntityTeleportEvent teleEvent; -@@ -3538,7 +3539,29 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (!to.equals(teleEvent.getTo())) { - to = teleEvent.getTo(); - teleportTarget = new TeleportTransition(((CraftWorld) to.getWorld()).getHandle(), CraftLocation.toVec3D(to), Vec3.ZERO, to.getYaw(), to.getPitch(), teleportTarget.missingRespawnBlock(), teleportTarget.asPassenger(), Set.of(), teleportTarget.postTeleportTransition(), teleportTarget.cause()); -+ // Paper start - Call EntityPortalExitEvent -+ velocity = Vec3.ZERO; - } -+ if (this.portalProcess != null) { // if in a portal -+ CraftEntity bukkitEntity = this.getBukkitEntity(); -+ org.bukkit.event.entity.EntityPortalExitEvent event = new org.bukkit.event.entity.EntityPortalExitEvent( -+ bukkitEntity, -+ bukkitEntity.getLocation(), to.clone(), -+ bukkitEntity.getVelocity(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(velocity) -+ ); -+ event.callEvent(); -+ -+ // Only change the target if actually needed, since we reset relative flags -+ if (!event.isCancelled() && event.getTo() != null && (!event.getTo().equals(event.getFrom()) || !event.getAfter().equals(event.getBefore()))) { -+ to = event.getTo().clone(); -+ velocity = org.bukkit.craftbukkit.util.CraftVector.toNMS(event.getAfter()); -+ teleportTarget = new TeleportTransition(((CraftWorld) to.getWorld()).getHandle(), CraftLocation.toVec3D(to), velocity, to.getYaw(), to.getPitch(), teleportTarget.missingRespawnBlock(), teleportTarget.asPassenger(), Set.of(), teleportTarget.postTeleportTransition(), teleportTarget.cause()); -+ } -+ } -+ if (this.isRemoved()) { -+ return null; -+ } -+ // Paper end - Call EntityPortalExitEvent - // CraftBukkit end - ServerLevel worldserver1 = teleportTarget.newLevel(); - boolean flag = worldserver1.dimension() != worldserver.dimension(); diff --git a/patches/server/0575-Add-methods-to-find-targets-for-lightning-strikes.patch b/patches/server/0575-Add-methods-to-find-targets-for-lightning-strikes.patch new file mode 100644 index 0000000000..b9b5d77d15 --- /dev/null +++ b/patches/server/0575-Add-methods-to-find-targets-for-lightning-strikes.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jakub Zacek +Date: Mon, 4 Oct 2021 10:16:44 +0200 +Subject: [PATCH] Add methods to find targets for lightning strikes + +== AT == +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 dc3d6bbbd79a0decc134f792d884962534717c0e..75d0143556dad6e830d3defdd9afecfd7587cdfa 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -741,6 +741,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } + + protected BlockPos findLightningTargetAround(BlockPos pos) { ++ // Paper start - Add methods to find targets for lightning strikes ++ return this.findLightningTargetAround(pos, false); ++ } ++ public BlockPos findLightningTargetAround(BlockPos pos, boolean returnNullWhenNoTarget) { ++ // Paper end - Add methods to find targets for lightning strikes + BlockPos blockposition1 = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos); + Optional optional = this.findLightningRod(blockposition1); + +@@ -755,6 +760,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (!list.isEmpty()) { + return ((LivingEntity) list.get(this.random.nextInt(list.size()))).blockPosition(); + } else { ++ if (returnNullWhenNoTarget) return null; // Paper - Add methods to find targets for lightning strikes + if (blockposition1.getY() == this.getMinY() - 1) { + blockposition1 = blockposition1.above(2); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index d72ceb866f8632a8daa7dc19acdc57b6b78fd906..d650822155f4628ea9d61ecbd4208520746aa59f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -676,6 +676,23 @@ public class CraftWorld extends CraftRegionAccessor implements World { + return (LightningStrike) lightning.getBukkitEntity(); + } + ++ // Paper start - Add methods to find targets for lightning strikes ++ @Override ++ public Location findLightningRod(Location location) { ++ return this.world.findLightningRod(io.papermc.paper.util.MCUtil.toBlockPosition(location)) ++ .map(blockPos -> io.papermc.paper.util.MCUtil.toLocation(this.world, blockPos) ++ // get the actual rod pos ++ .subtract(0, 1, 0)) ++ .orElse(null); ++ } ++ ++ @Override ++ public Location findLightningTarget(Location location) { ++ final BlockPos pos = this.world.findLightningTargetAround(io.papermc.paper.util.MCUtil.toBlockPosition(location), true); ++ return pos == null ? null : io.papermc.paper.util.MCUtil.toLocation(this.world, pos); ++ } ++ // Paper end - Add methods to find targets for lightning strikes ++ + @Override + public boolean generateTree(Location loc, TreeType type) { + return this.generateTree(loc, CraftWorld.rand, type); diff --git a/patches/server/0576-Add-methods-to-find-targets-for-lightning-strikes.patch b/patches/server/0576-Add-methods-to-find-targets-for-lightning-strikes.patch deleted file mode 100644 index a21e15c6fc..0000000000 --- a/patches/server/0576-Add-methods-to-find-targets-for-lightning-strikes.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jakub Zacek -Date: Mon, 4 Oct 2021 10:16:44 +0200 -Subject: [PATCH] Add methods to find targets for lightning strikes - -== AT == -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 93656336af194994f59072fa89bfc338d89d76af..e6ff03143b3639f375323393814b1256b98687ad 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -741,6 +741,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - - protected BlockPos findLightningTargetAround(BlockPos pos) { -+ // Paper start - Add methods to find targets for lightning strikes -+ return this.findLightningTargetAround(pos, false); -+ } -+ public BlockPos findLightningTargetAround(BlockPos pos, boolean returnNullWhenNoTarget) { -+ // Paper end - Add methods to find targets for lightning strikes - BlockPos blockposition1 = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos); - Optional optional = this.findLightningRod(blockposition1); - -@@ -755,6 +760,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (!list.isEmpty()) { - return ((LivingEntity) list.get(this.random.nextInt(list.size()))).blockPosition(); - } else { -+ if (returnNullWhenNoTarget) return null; // Paper - Add methods to find targets for lightning strikes - if (blockposition1.getY() == this.getMinY() - 1) { - blockposition1 = blockposition1.above(2); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index d72ceb866f8632a8daa7dc19acdc57b6b78fd906..d650822155f4628ea9d61ecbd4208520746aa59f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -676,6 +676,23 @@ public class CraftWorld extends CraftRegionAccessor implements World { - return (LightningStrike) lightning.getBukkitEntity(); - } - -+ // Paper start - Add methods to find targets for lightning strikes -+ @Override -+ public Location findLightningRod(Location location) { -+ return this.world.findLightningRod(io.papermc.paper.util.MCUtil.toBlockPosition(location)) -+ .map(blockPos -> io.papermc.paper.util.MCUtil.toLocation(this.world, blockPos) -+ // get the actual rod pos -+ .subtract(0, 1, 0)) -+ .orElse(null); -+ } -+ -+ @Override -+ public Location findLightningTarget(Location location) { -+ final BlockPos pos = this.world.findLightningTargetAround(io.papermc.paper.util.MCUtil.toBlockPosition(location), true); -+ return pos == null ? null : io.papermc.paper.util.MCUtil.toLocation(this.world, pos); -+ } -+ // Paper end - Add methods to find targets for lightning strikes -+ - @Override - public boolean generateTree(Location loc, TreeType type) { - return this.generateTree(loc, CraftWorld.rand, type); diff --git a/patches/server/0576-Get-entity-default-attributes.patch b/patches/server/0576-Get-entity-default-attributes.patch new file mode 100644 index 0000000000..1f2a14bb52 --- /dev/null +++ b/patches/server/0576-Get-entity-default-attributes.patch @@ -0,0 +1,151 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 20 Aug 2021 13:03:21 -0700 +Subject: [PATCH] Get entity default attributes + +== AT == +public net.minecraft.world.entity.ai.attributes.AttributeSupplier getAttributeInstance(Lnet/minecraft/core/Holder;)Lnet/minecraft/world/entity/ai/attributes/AttributeInstance; + +diff --git a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java +new file mode 100644 +index 0000000000000000000000000000000000000000..12135ffeacd648f6bc4d7d327059ea1a7e8c79c4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.attribute; ++ ++import net.minecraft.world.entity.ai.attributes.AttributeInstance; ++import org.bukkit.attribute.Attribute; ++import org.bukkit.attribute.AttributeModifier; ++import org.bukkit.craftbukkit.attribute.CraftAttributeInstance; ++ ++import java.util.Collection; ++ ++public class UnmodifiableAttributeInstance extends CraftAttributeInstance { ++ ++ public UnmodifiableAttributeInstance(AttributeInstance handle, Attribute attribute) { ++ super(handle, attribute); ++ } ++ ++ @Override ++ public void setBaseValue(double d) { ++ throw new UnsupportedOperationException("Cannot modify default attributes"); ++ } ++ ++ @Override ++ public void addModifier(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/io/papermc/paper/attribute/UnmodifiableAttributeMap.java b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeMap.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ec9ebd2d539333293c51b7edfa18f18b066d7e43 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeMap.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.attribute; ++ ++import net.minecraft.world.entity.ai.attributes.AttributeSupplier; ++import org.bukkit.attribute.Attributable; ++import org.bukkit.attribute.Attribute; ++import org.bukkit.attribute.AttributeInstance; ++import org.bukkit.craftbukkit.attribute.CraftAttribute; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class UnmodifiableAttributeMap implements Attributable { ++ ++ private final AttributeSupplier handle; ++ ++ public UnmodifiableAttributeMap(@NotNull AttributeSupplier handle) { ++ this.handle = handle; ++ } ++ ++ @Override ++ public @Nullable AttributeInstance getAttribute(@NotNull Attribute attribute) { ++ net.minecraft.core.Holder nmsAttribute = CraftAttribute.bukkitToMinecraftHolder(attribute); ++ if (!this.handle.hasAttribute(nmsAttribute)) { ++ return null; ++ } ++ return new UnmodifiableAttributeInstance(this.handle.getAttributeInstance(nmsAttribute), attribute); ++ } ++ ++ @Override ++ public void registerAttribute(@NotNull Attribute attribute) { ++ throw new UnsupportedOperationException("Cannot register new attributes here"); ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index e613ea0eba9a1d162b8f7dfe32c9c31d82f17dd2..6f780b76ebadb6155195b93f3e6d382141eb0bcc 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -560,6 +560,18 @@ public final class CraftMagicNumbers implements UnsafeValues { + } + return CraftItemStack.unwrap(itemToBeRepaired).isValidRepairItem(CraftItemStack.unwrap(repairMaterial)); + } ++ ++ @Override ++ public boolean hasDefaultEntityAttributes(NamespacedKey bukkitEntityKey) { ++ return net.minecraft.world.entity.ai.attributes.DefaultAttributes.hasSupplier(net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getValue(CraftNamespacedKey.toMinecraft(bukkitEntityKey))); ++ } ++ ++ @Override ++ public org.bukkit.attribute.Attributable getDefaultEntityAttributes(NamespacedKey bukkitEntityKey) { ++ Preconditions.checkArgument(hasDefaultEntityAttributes(bukkitEntityKey), bukkitEntityKey + " doesn't have default attributes"); ++ 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); ++ } + // Paper end + + /** +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..fa9fb37993f4025f85dac084efb4b5eda0ede637 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/attribute/EntityTypeAttributesTest.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.attribute; ++ ++import org.bukkit.attribute.Attributable; ++import org.bukkit.attribute.Attribute; ++import org.bukkit.attribute.AttributeInstance; ++import org.bukkit.attribute.AttributeModifier; ++import org.bukkit.entity.EntityType; ++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.assertNotNull; ++import static org.junit.jupiter.api.Assertions.assertThrows; ++import static org.junit.jupiter.api.Assertions.assertTrue; ++ ++@AllFeatures ++public class EntityTypeAttributesTest { ++ ++ @Test ++ public void testIllegalEntity() { ++ assertFalse(EntityType.EGG.hasDefaultAttributes()); ++ assertThrows(IllegalArgumentException.class, EntityType.EGG::getDefaultAttributes); ++ } ++ ++ @Test ++ public void testLegalEntity() { ++ assertTrue(EntityType.ZOMBIE.hasDefaultAttributes()); ++ EntityType.ZOMBIE.getDefaultAttributes(); ++ } ++ ++ @Test ++ public void testUnmodifiabilityOfAttributable() { ++ Attributable attributable = EntityType.ZOMBIE.getDefaultAttributes(); ++ assertThrows(UnsupportedOperationException.class, () -> attributable.registerAttribute(Attribute.ATTACK_DAMAGE)); ++ AttributeInstance instance = attributable.getAttribute(Attribute.FOLLOW_RANGE); ++ assertNotNull(instance); ++ assertThrows(UnsupportedOperationException.class, () -> instance.addModifier(new AttributeModifier("test", 3, AttributeModifier.Operation.ADD_NUMBER))); ++ assertThrows(UnsupportedOperationException.class, () -> instance.setBaseValue(3.2)); ++ } ++} diff --git a/patches/server/0577-Get-entity-default-attributes.patch b/patches/server/0577-Get-entity-default-attributes.patch deleted file mode 100644 index 1f2a14bb52..0000000000 --- a/patches/server/0577-Get-entity-default-attributes.patch +++ /dev/null @@ -1,151 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 20 Aug 2021 13:03:21 -0700 -Subject: [PATCH] Get entity default attributes - -== AT == -public net.minecraft.world.entity.ai.attributes.AttributeSupplier getAttributeInstance(Lnet/minecraft/core/Holder;)Lnet/minecraft/world/entity/ai/attributes/AttributeInstance; - -diff --git a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java -new file mode 100644 -index 0000000000000000000000000000000000000000..12135ffeacd648f6bc4d7d327059ea1a7e8c79c4 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java -@@ -0,0 +1,30 @@ -+package io.papermc.paper.attribute; -+ -+import net.minecraft.world.entity.ai.attributes.AttributeInstance; -+import org.bukkit.attribute.Attribute; -+import org.bukkit.attribute.AttributeModifier; -+import org.bukkit.craftbukkit.attribute.CraftAttributeInstance; -+ -+import java.util.Collection; -+ -+public class UnmodifiableAttributeInstance extends CraftAttributeInstance { -+ -+ public UnmodifiableAttributeInstance(AttributeInstance handle, Attribute attribute) { -+ super(handle, attribute); -+ } -+ -+ @Override -+ public void setBaseValue(double d) { -+ throw new UnsupportedOperationException("Cannot modify default attributes"); -+ } -+ -+ @Override -+ public void addModifier(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/io/papermc/paper/attribute/UnmodifiableAttributeMap.java b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ec9ebd2d539333293c51b7edfa18f18b066d7e43 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeMap.java -@@ -0,0 +1,32 @@ -+package io.papermc.paper.attribute; -+ -+import net.minecraft.world.entity.ai.attributes.AttributeSupplier; -+import org.bukkit.attribute.Attributable; -+import org.bukkit.attribute.Attribute; -+import org.bukkit.attribute.AttributeInstance; -+import org.bukkit.craftbukkit.attribute.CraftAttribute; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class UnmodifiableAttributeMap implements Attributable { -+ -+ private final AttributeSupplier handle; -+ -+ public UnmodifiableAttributeMap(@NotNull AttributeSupplier handle) { -+ this.handle = handle; -+ } -+ -+ @Override -+ public @Nullable AttributeInstance getAttribute(@NotNull Attribute attribute) { -+ net.minecraft.core.Holder nmsAttribute = CraftAttribute.bukkitToMinecraftHolder(attribute); -+ if (!this.handle.hasAttribute(nmsAttribute)) { -+ return null; -+ } -+ return new UnmodifiableAttributeInstance(this.handle.getAttributeInstance(nmsAttribute), attribute); -+ } -+ -+ @Override -+ public void registerAttribute(@NotNull Attribute attribute) { -+ throw new UnsupportedOperationException("Cannot register new attributes here"); -+ } -+} -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index e613ea0eba9a1d162b8f7dfe32c9c31d82f17dd2..6f780b76ebadb6155195b93f3e6d382141eb0bcc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -560,6 +560,18 @@ public final class CraftMagicNumbers implements UnsafeValues { - } - return CraftItemStack.unwrap(itemToBeRepaired).isValidRepairItem(CraftItemStack.unwrap(repairMaterial)); - } -+ -+ @Override -+ public boolean hasDefaultEntityAttributes(NamespacedKey bukkitEntityKey) { -+ return net.minecraft.world.entity.ai.attributes.DefaultAttributes.hasSupplier(net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getValue(CraftNamespacedKey.toMinecraft(bukkitEntityKey))); -+ } -+ -+ @Override -+ public org.bukkit.attribute.Attributable getDefaultEntityAttributes(NamespacedKey bukkitEntityKey) { -+ Preconditions.checkArgument(hasDefaultEntityAttributes(bukkitEntityKey), bukkitEntityKey + " doesn't have default attributes"); -+ 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); -+ } - // Paper end - - /** -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..fa9fb37993f4025f85dac084efb4b5eda0ede637 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/attribute/EntityTypeAttributesTest.java -@@ -0,0 +1,40 @@ -+package io.papermc.paper.attribute; -+ -+import org.bukkit.attribute.Attributable; -+import org.bukkit.attribute.Attribute; -+import org.bukkit.attribute.AttributeInstance; -+import org.bukkit.attribute.AttributeModifier; -+import org.bukkit.entity.EntityType; -+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.assertNotNull; -+import static org.junit.jupiter.api.Assertions.assertThrows; -+import static org.junit.jupiter.api.Assertions.assertTrue; -+ -+@AllFeatures -+public class EntityTypeAttributesTest { -+ -+ @Test -+ public void testIllegalEntity() { -+ assertFalse(EntityType.EGG.hasDefaultAttributes()); -+ assertThrows(IllegalArgumentException.class, EntityType.EGG::getDefaultAttributes); -+ } -+ -+ @Test -+ public void testLegalEntity() { -+ assertTrue(EntityType.ZOMBIE.hasDefaultAttributes()); -+ EntityType.ZOMBIE.getDefaultAttributes(); -+ } -+ -+ @Test -+ public void testUnmodifiabilityOfAttributable() { -+ Attributable attributable = EntityType.ZOMBIE.getDefaultAttributes(); -+ assertThrows(UnsupportedOperationException.class, () -> attributable.registerAttribute(Attribute.ATTACK_DAMAGE)); -+ AttributeInstance instance = attributable.getAttribute(Attribute.FOLLOW_RANGE); -+ assertNotNull(instance); -+ assertThrows(UnsupportedOperationException.class, () -> instance.addModifier(new AttributeModifier("test", 3, AttributeModifier.Operation.ADD_NUMBER))); -+ assertThrows(UnsupportedOperationException.class, () -> instance.setBaseValue(3.2)); -+ } -+} diff --git a/patches/server/0577-Left-handed-API.patch b/patches/server/0577-Left-handed-API.patch new file mode 100644 index 0000000000..50bb0d4ebe --- /dev/null +++ b/patches/server/0577-Left-handed-API.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 14 Oct 2021 12:36:58 -0500 +Subject: [PATCH] Left handed API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +index 7cf42f62d91c131b1cab576979f85c58c3cecb3b..e226a99d00c990a4ca4f21b93fcae7a556e01dbb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +@@ -145,6 +145,16 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { + public int getMaxHeadPitch() { + return getHandle().getMaxHeadXRot(); + } ++ ++ @Override ++ public boolean isLeftHanded() { ++ return getHandle().isLeftHanded(); ++ } ++ ++ @Override ++ public void setLeftHanded(boolean leftHanded) { ++ getHandle().setLeftHanded(leftHanded); ++ } + // Paper end + + // Paper start diff --git a/patches/server/0578-Add-more-advancement-API.patch b/patches/server/0578-Add-more-advancement-API.patch new file mode 100644 index 0000000000..70ac177106 --- /dev/null +++ b/patches/server/0578-Add-more-advancement-API.patch @@ -0,0 +1,213 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: syldium +Date: Fri, 9 Jul 2021 18:50:40 +0200 +Subject: [PATCH] Add more advancement API + +== AT == +public net.minecraft.advancements.Advancement decorateName(Lnet/minecraft/advancements/DisplayInfo;)Lnet/minecraft/network/chat/Component; + +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java b/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java +new file mode 100644 +index 0000000000000000000000000000000000000000..adac21ce6db3ff7a56dbcd6bffc02143c2db4046 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java +@@ -0,0 +1,69 @@ ++package io.papermc.paper.advancement; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.text.Component; ++import net.minecraft.advancements.Advancement; ++import net.minecraft.advancements.AdvancementType; ++import net.minecraft.advancements.DisplayInfo; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public record PaperAdvancementDisplay(DisplayInfo handle) implements AdvancementDisplay { ++ ++ @Override ++ public @NotNull Frame frame() { ++ return asPaperFrame(this.handle.getType()); ++ } ++ ++ @Override ++ public @NotNull Component title() { ++ return PaperAdventure.asAdventure(this.handle.getTitle()); ++ } ++ ++ @Override ++ public @NotNull Component description() { ++ return PaperAdventure.asAdventure(this.handle.getDescription()); ++ } ++ ++ @Override ++ public @NotNull ItemStack icon() { ++ return CraftItemStack.asBukkitCopy(this.handle.getIcon()); ++ } ++ ++ @Override ++ public boolean doesShowToast() { ++ return this.handle.shouldShowToast(); ++ } ++ ++ @Override ++ public boolean doesAnnounceToChat() { ++ return this.handle.shouldAnnounceChat(); ++ } ++ ++ @Override ++ public boolean isHidden() { ++ return this.handle.isHidden(); ++ } ++ ++ @Override ++ public @Nullable NamespacedKey backgroundPath() { ++ return this.handle.getBackground().map(CraftNamespacedKey::fromMinecraft).orElse(null); ++ } ++ ++ @Override ++ public @NotNull Component displayName() { ++ return PaperAdventure.asAdventure(Advancement.decorateName(java.util.Objects.requireNonNull(this.handle, "cannot build display name for null handle, invalid state"))); ++ } ++ ++ public static @NotNull Frame asPaperFrame(final @NotNull AdvancementType frameType) { ++ return switch (frameType) { ++ case TASK -> Frame.TASK; ++ case CHALLENGE -> Frame.CHALLENGE; ++ case GOAL -> Frame.GOAL; ++ }; ++ } ++} +diff --git a/src/main/java/net/minecraft/advancements/DisplayInfo.java b/src/main/java/net/minecraft/advancements/DisplayInfo.java +index 05de12414a3ad1c8f0f02f7973898dda84b89b82..6581cdbec730d5d184566e7b611369b3c424fecf 100644 +--- a/src/main/java/net/minecraft/advancements/DisplayInfo.java ++++ b/src/main/java/net/minecraft/advancements/DisplayInfo.java +@@ -37,6 +37,7 @@ public class DisplayInfo { + private final boolean hidden; + private float x; + private float y; ++ public final io.papermc.paper.advancement.AdvancementDisplay paper = new io.papermc.paper.advancement.PaperAdvancementDisplay(this); // Paper - Add more advancement API + + public DisplayInfo( + ItemStack icon, +diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java +index d119093d3a68c5a378fcd20860e36dbd2ba5024f..d12d9913f15c274df9c23f68e4e0304d41fccbdb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java ++++ b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java +@@ -35,12 +35,47 @@ public class CraftAdvancement implements org.bukkit.advancement.Advancement { + return new CraftAdvancementRequirements(this.handle.value().requirements()); + } + ++ // Paper start - Add more advancement API + @Override +- public AdvancementDisplay getDisplay() { +- if (this.handle.value().display().isEmpty()) { +- return null; ++ public io.papermc.paper.advancement.AdvancementDisplay getDisplay() { ++ return this.handle.value().display().map(d -> d.paper).orElse(null); ++ } ++ ++ @Deprecated ++ @io.papermc.paper.annotation.DoNotUse ++ public AdvancementDisplay getDisplay0() { // May be called by plugins via Commodore ++ return this.handle.value().display().map(CraftAdvancementDisplay::new).orElse(null); ++ } ++ ++ @Override ++ public net.kyori.adventure.text.Component displayName() { ++ return io.papermc.paper.adventure.PaperAdventure.asAdventure(net.minecraft.advancements.Advancement.name(this.handle)); ++ } ++ ++ @Override ++ public org.bukkit.advancement.Advancement getParent() { ++ return this.handle.value().parent() ++ .map(net.minecraft.server.MinecraftServer.getServer().getAdvancements()::get) ++ .map(AdvancementHolder::toBukkit) ++ .orElse(null); ++ } ++ ++ @Override ++ public Collection getChildren() { ++ final com.google.common.collect.ImmutableList.Builder children = com.google.common.collect.ImmutableList.builder(); ++ final net.minecraft.advancements.AdvancementNode advancementNode = net.minecraft.server.MinecraftServer.getServer().getAdvancements().tree().get(this.handle); ++ if (advancementNode != null) { ++ for (final net.minecraft.advancements.AdvancementNode child : advancementNode.children()) { ++ children.add(child.holder().toBukkit()); ++ } + } ++ return children.build(); ++ } + +- return new CraftAdvancementDisplay(this.handle.value().display().get()); ++ @Override ++ public org.bukkit.advancement.Advancement getRoot() { ++ final net.minecraft.advancements.AdvancementNode advancementNode = net.minecraft.server.MinecraftServer.getServer().getAdvancements().tree().get(this.handle); ++ return java.util.Objects.requireNonNull(advancementNode, "could not find internal advancement node for advancement " + this.handle.id()).root().holder().toBukkit(); + } ++ // Paper end - Add more advancement API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java +index 8ca86852319d7463f60832bc98b825b0b4325995..62ada73302c6b3ce3fb2dcc8c31a1d9c0ac4fd09 100644 +--- a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java ++++ b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java +@@ -6,6 +6,7 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack; + import org.bukkit.craftbukkit.util.CraftChatMessage; + import org.bukkit.inventory.ItemStack; + ++@Deprecated // Paper + public class CraftAdvancementDisplay implements org.bukkit.advancement.AdvancementDisplay { + + private final DisplayInfo handle; +diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +index c9b789c2a904c2caff516ee9aeff4a6b368766f4..52a507ff2770bd46494e805956b4569f0d4d21ee 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +@@ -458,6 +458,11 @@ public class Commodore { + super.visitMethodInsn(opcode, owner, name, "()Lcom/destroystokyo/paper/profile/PlayerProfile;", itf); + return; + } ++ if (owner.equals("org/bukkit/advancement/Advancement") && name.equals("getDisplay") && desc.endsWith(")Lorg/bukkit/advancement/AdvancementDisplay;")) { ++ super.visitTypeInsn(Opcodes.CHECKCAST, runtimeCbPkgPrefix() + "advancement/CraftAdvancement"); ++ super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, runtimeCbPkgPrefix() + "advancement/CraftAdvancement", "getDisplay0", desc, false); ++ return; ++ } + // Paper end + + if (modern) { +diff --git a/src/test/java/io/papermc/paper/advancement/AdvancementFrameTest.java b/src/test/java/io/papermc/paper/advancement/AdvancementFrameTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6fe9c10ffd1dd5244ead05642609794623054cce +--- /dev/null ++++ b/src/test/java/io/papermc/paper/advancement/AdvancementFrameTest.java +@@ -0,0 +1,26 @@ ++package io.papermc.paper.advancement; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.text.format.TextColor; ++import net.minecraft.advancements.AdvancementType; ++import net.minecraft.network.chat.contents.TranslatableContents; ++import org.bukkit.support.environment.Normal; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertEquals; ++ ++@Normal ++public class AdvancementFrameTest { ++ ++ @Test ++ public void test() { ++ for (final AdvancementType advancementType : AdvancementType.values()) { ++ final TextColor expectedColor = PaperAdventure.asAdventure(advancementType.getChatColor()); ++ final String expectedTranslationKey = ((TranslatableContents) advancementType.getDisplayName().getContents()).getKey(); ++ final var frame = PaperAdvancementDisplay.asPaperFrame(advancementType); ++ assertEquals(expectedTranslationKey, frame.translationKey(), "The translation keys should be the same"); ++ assertEquals(expectedColor, frame.color(), "The frame colors should be the same"); ++ assertEquals(advancementType.getSerializedName(), AdvancementDisplay.Frame.NAMES.key(frame)); ++ } ++ } ++} diff --git a/patches/server/0578-Left-handed-API.patch b/patches/server/0578-Left-handed-API.patch deleted file mode 100644 index 50bb0d4ebe..0000000000 --- a/patches/server/0578-Left-handed-API.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 14 Oct 2021 12:36:58 -0500 -Subject: [PATCH] Left handed API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -index 7cf42f62d91c131b1cab576979f85c58c3cecb3b..e226a99d00c990a4ca4f21b93fcae7a556e01dbb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -@@ -145,6 +145,16 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { - public int getMaxHeadPitch() { - return getHandle().getMaxHeadXRot(); - } -+ -+ @Override -+ public boolean isLeftHanded() { -+ return getHandle().isLeftHanded(); -+ } -+ -+ @Override -+ public void setLeftHanded(boolean leftHanded) { -+ getHandle().setLeftHanded(leftHanded); -+ } - // Paper end - - // Paper start diff --git a/patches/server/0579-Add-ItemFactory-getSpawnEgg-API.patch b/patches/server/0579-Add-ItemFactory-getSpawnEgg-API.patch new file mode 100644 index 0000000000..b15779d35b --- /dev/null +++ b/patches/server/0579-Add-ItemFactory-getSpawnEgg-API.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 14 Oct 2021 12:09:39 -0500 +Subject: [PATCH] Add ItemFactory#getSpawnEgg API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +index 68798c90f2a116d82f6f25e920c54c929df6fca9..a04840b77e2d84e754c9cfa79bc593608bc22c90 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +@@ -9,6 +9,7 @@ import net.minecraft.core.HolderSet; + import net.minecraft.core.RegistryAccess; + import net.minecraft.core.component.DataComponentPatch; + import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceLocation; + import net.minecraft.server.MinecraftServer; + import net.minecraft.tags.EnchantmentTags; + import net.minecraft.util.RandomSource; +@@ -291,4 +292,19 @@ public final class CraftItemFactory implements ItemFactory { + new net.md_5.bungee.api.chat.TextComponent(customName)); + } + // Paper end - bungee hover events ++ ++ // Paper start - old getSpawnEgg API ++ // @Override // used to override, upstream added conflicting method, is called via Commodore now ++ @Deprecated ++ public ItemStack getSpawnEgg0(org.bukkit.entity.EntityType type) { ++ if (type == null) { ++ return null; ++ } ++ String typeId = type.getKey().toString(); ++ net.minecraft.resources.ResourceLocation typeKey = ResourceLocation.parse(typeId); ++ net.minecraft.world.entity.EntityType nmsType = net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getValue(typeKey); ++ net.minecraft.world.item.SpawnEggItem eggItem = net.minecraft.world.item.SpawnEggItem.byId(nmsType); ++ return eggItem == null ? null : new net.minecraft.world.item.ItemStack(eggItem).asBukkitMirror(); ++ } ++ // Paper end - old getSpawnEgg API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +index 52a507ff2770bd46494e805956b4569f0d4d21ee..5a7aa491e0846ca8133bc4bb6e74b93cff85fb17 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +@@ -465,6 +465,15 @@ public class Commodore { + } + // Paper end + ++ // Paper start - ItemFactory#getSpawnEgg (paper had original method that returned ItemStack, upstream added identical but returned Material) ++ if (owner.equals("org/bukkit/inventory/ItemFactory") && name.equals("getSpawnEgg") && desc.equals("(Lorg/bukkit/entity/EntityType;)Lorg/bukkit/inventory/ItemStack;")) { ++ super.visitInsn(Opcodes.SWAP); // has 1 param, this moves the owner instance to the top for the checkcast ++ super.visitTypeInsn(Opcodes.CHECKCAST, runtimeCbPkgPrefix() + "inventory/CraftItemFactory"); ++ super.visitInsn(Opcodes.SWAP); // moves param back to the the top of stack ++ super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, runtimeCbPkgPrefix() + "inventory/CraftItemFactory", "getSpawnEgg0", desc, false); ++ return; ++ } ++ // Paper end - ItemFactory#getSpawnEgg + if (modern) { + if (owner.equals("org/bukkit/Material") || (instantiatedMethodType != null && instantiatedMethodType.getDescriptor().startsWith("(Lorg/bukkit/Material;)"))) { + switch (name) { diff --git a/patches/server/0579-Add-more-advancement-API.patch b/patches/server/0579-Add-more-advancement-API.patch deleted file mode 100644 index 70ac177106..0000000000 --- a/patches/server/0579-Add-more-advancement-API.patch +++ /dev/null @@ -1,213 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: syldium -Date: Fri, 9 Jul 2021 18:50:40 +0200 -Subject: [PATCH] Add more advancement API - -== AT == -public net.minecraft.advancements.Advancement decorateName(Lnet/minecraft/advancements/DisplayInfo;)Lnet/minecraft/network/chat/Component; - -Co-authored-by: Jake Potrebic - -diff --git a/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java b/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java -new file mode 100644 -index 0000000000000000000000000000000000000000..adac21ce6db3ff7a56dbcd6bffc02143c2db4046 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java -@@ -0,0 +1,69 @@ -+package io.papermc.paper.advancement; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import net.kyori.adventure.text.Component; -+import net.minecraft.advancements.Advancement; -+import net.minecraft.advancements.AdvancementType; -+import net.minecraft.advancements.DisplayInfo; -+import org.bukkit.NamespacedKey; -+import org.bukkit.craftbukkit.inventory.CraftItemStack; -+import org.bukkit.craftbukkit.util.CraftNamespacedKey; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public record PaperAdvancementDisplay(DisplayInfo handle) implements AdvancementDisplay { -+ -+ @Override -+ public @NotNull Frame frame() { -+ return asPaperFrame(this.handle.getType()); -+ } -+ -+ @Override -+ public @NotNull Component title() { -+ return PaperAdventure.asAdventure(this.handle.getTitle()); -+ } -+ -+ @Override -+ public @NotNull Component description() { -+ return PaperAdventure.asAdventure(this.handle.getDescription()); -+ } -+ -+ @Override -+ public @NotNull ItemStack icon() { -+ return CraftItemStack.asBukkitCopy(this.handle.getIcon()); -+ } -+ -+ @Override -+ public boolean doesShowToast() { -+ return this.handle.shouldShowToast(); -+ } -+ -+ @Override -+ public boolean doesAnnounceToChat() { -+ return this.handle.shouldAnnounceChat(); -+ } -+ -+ @Override -+ public boolean isHidden() { -+ return this.handle.isHidden(); -+ } -+ -+ @Override -+ public @Nullable NamespacedKey backgroundPath() { -+ return this.handle.getBackground().map(CraftNamespacedKey::fromMinecraft).orElse(null); -+ } -+ -+ @Override -+ public @NotNull Component displayName() { -+ return PaperAdventure.asAdventure(Advancement.decorateName(java.util.Objects.requireNonNull(this.handle, "cannot build display name for null handle, invalid state"))); -+ } -+ -+ public static @NotNull Frame asPaperFrame(final @NotNull AdvancementType frameType) { -+ return switch (frameType) { -+ case TASK -> Frame.TASK; -+ case CHALLENGE -> Frame.CHALLENGE; -+ case GOAL -> Frame.GOAL; -+ }; -+ } -+} -diff --git a/src/main/java/net/minecraft/advancements/DisplayInfo.java b/src/main/java/net/minecraft/advancements/DisplayInfo.java -index 05de12414a3ad1c8f0f02f7973898dda84b89b82..6581cdbec730d5d184566e7b611369b3c424fecf 100644 ---- a/src/main/java/net/minecraft/advancements/DisplayInfo.java -+++ b/src/main/java/net/minecraft/advancements/DisplayInfo.java -@@ -37,6 +37,7 @@ public class DisplayInfo { - private final boolean hidden; - private float x; - private float y; -+ public final io.papermc.paper.advancement.AdvancementDisplay paper = new io.papermc.paper.advancement.PaperAdvancementDisplay(this); // Paper - Add more advancement API - - public DisplayInfo( - ItemStack icon, -diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java -index d119093d3a68c5a378fcd20860e36dbd2ba5024f..d12d9913f15c274df9c23f68e4e0304d41fccbdb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java -+++ b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java -@@ -35,12 +35,47 @@ public class CraftAdvancement implements org.bukkit.advancement.Advancement { - return new CraftAdvancementRequirements(this.handle.value().requirements()); - } - -+ // Paper start - Add more advancement API - @Override -- public AdvancementDisplay getDisplay() { -- if (this.handle.value().display().isEmpty()) { -- return null; -+ public io.papermc.paper.advancement.AdvancementDisplay getDisplay() { -+ return this.handle.value().display().map(d -> d.paper).orElse(null); -+ } -+ -+ @Deprecated -+ @io.papermc.paper.annotation.DoNotUse -+ public AdvancementDisplay getDisplay0() { // May be called by plugins via Commodore -+ return this.handle.value().display().map(CraftAdvancementDisplay::new).orElse(null); -+ } -+ -+ @Override -+ public net.kyori.adventure.text.Component displayName() { -+ return io.papermc.paper.adventure.PaperAdventure.asAdventure(net.minecraft.advancements.Advancement.name(this.handle)); -+ } -+ -+ @Override -+ public org.bukkit.advancement.Advancement getParent() { -+ return this.handle.value().parent() -+ .map(net.minecraft.server.MinecraftServer.getServer().getAdvancements()::get) -+ .map(AdvancementHolder::toBukkit) -+ .orElse(null); -+ } -+ -+ @Override -+ public Collection getChildren() { -+ final com.google.common.collect.ImmutableList.Builder children = com.google.common.collect.ImmutableList.builder(); -+ final net.minecraft.advancements.AdvancementNode advancementNode = net.minecraft.server.MinecraftServer.getServer().getAdvancements().tree().get(this.handle); -+ if (advancementNode != null) { -+ for (final net.minecraft.advancements.AdvancementNode child : advancementNode.children()) { -+ children.add(child.holder().toBukkit()); -+ } - } -+ return children.build(); -+ } - -- return new CraftAdvancementDisplay(this.handle.value().display().get()); -+ @Override -+ public org.bukkit.advancement.Advancement getRoot() { -+ final net.minecraft.advancements.AdvancementNode advancementNode = net.minecraft.server.MinecraftServer.getServer().getAdvancements().tree().get(this.handle); -+ return java.util.Objects.requireNonNull(advancementNode, "could not find internal advancement node for advancement " + this.handle.id()).root().holder().toBukkit(); - } -+ // Paper end - Add more advancement API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java -index 8ca86852319d7463f60832bc98b825b0b4325995..62ada73302c6b3ce3fb2dcc8c31a1d9c0ac4fd09 100644 ---- a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java -+++ b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java -@@ -6,6 +6,7 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack; - import org.bukkit.craftbukkit.util.CraftChatMessage; - import org.bukkit.inventory.ItemStack; - -+@Deprecated // Paper - public class CraftAdvancementDisplay implements org.bukkit.advancement.AdvancementDisplay { - - private final DisplayInfo handle; -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -index c9b789c2a904c2caff516ee9aeff4a6b368766f4..52a507ff2770bd46494e805956b4569f0d4d21ee 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -@@ -458,6 +458,11 @@ public class Commodore { - super.visitMethodInsn(opcode, owner, name, "()Lcom/destroystokyo/paper/profile/PlayerProfile;", itf); - return; - } -+ if (owner.equals("org/bukkit/advancement/Advancement") && name.equals("getDisplay") && desc.endsWith(")Lorg/bukkit/advancement/AdvancementDisplay;")) { -+ super.visitTypeInsn(Opcodes.CHECKCAST, runtimeCbPkgPrefix() + "advancement/CraftAdvancement"); -+ super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, runtimeCbPkgPrefix() + "advancement/CraftAdvancement", "getDisplay0", desc, false); -+ return; -+ } - // Paper end - - if (modern) { -diff --git a/src/test/java/io/papermc/paper/advancement/AdvancementFrameTest.java b/src/test/java/io/papermc/paper/advancement/AdvancementFrameTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6fe9c10ffd1dd5244ead05642609794623054cce ---- /dev/null -+++ b/src/test/java/io/papermc/paper/advancement/AdvancementFrameTest.java -@@ -0,0 +1,26 @@ -+package io.papermc.paper.advancement; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import net.kyori.adventure.text.format.TextColor; -+import net.minecraft.advancements.AdvancementType; -+import net.minecraft.network.chat.contents.TranslatableContents; -+import org.bukkit.support.environment.Normal; -+import org.junit.jupiter.api.Test; -+ -+import static org.junit.jupiter.api.Assertions.assertEquals; -+ -+@Normal -+public class AdvancementFrameTest { -+ -+ @Test -+ public void test() { -+ for (final AdvancementType advancementType : AdvancementType.values()) { -+ final TextColor expectedColor = PaperAdventure.asAdventure(advancementType.getChatColor()); -+ final String expectedTranslationKey = ((TranslatableContents) advancementType.getDisplayName().getContents()).getKey(); -+ final var frame = PaperAdvancementDisplay.asPaperFrame(advancementType); -+ assertEquals(expectedTranslationKey, frame.translationKey(), "The translation keys should be the same"); -+ assertEquals(expectedColor, frame.color(), "The frame colors should be the same"); -+ assertEquals(advancementType.getSerializedName(), AdvancementDisplay.Frame.NAMES.key(frame)); -+ } -+ } -+} diff --git a/patches/server/0580-Add-ItemFactory-getSpawnEgg-API.patch b/patches/server/0580-Add-ItemFactory-getSpawnEgg-API.patch deleted file mode 100644 index b15779d35b..0000000000 --- a/patches/server/0580-Add-ItemFactory-getSpawnEgg-API.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 14 Oct 2021 12:09:39 -0500 -Subject: [PATCH] Add ItemFactory#getSpawnEgg API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -index 68798c90f2a116d82f6f25e920c54c929df6fca9..a04840b77e2d84e754c9cfa79bc593608bc22c90 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -@@ -9,6 +9,7 @@ import net.minecraft.core.HolderSet; - import net.minecraft.core.RegistryAccess; - import net.minecraft.core.component.DataComponentPatch; - import net.minecraft.core.registries.Registries; -+import net.minecraft.resources.ResourceLocation; - import net.minecraft.server.MinecraftServer; - import net.minecraft.tags.EnchantmentTags; - import net.minecraft.util.RandomSource; -@@ -291,4 +292,19 @@ public final class CraftItemFactory implements ItemFactory { - new net.md_5.bungee.api.chat.TextComponent(customName)); - } - // Paper end - bungee hover events -+ -+ // Paper start - old getSpawnEgg API -+ // @Override // used to override, upstream added conflicting method, is called via Commodore now -+ @Deprecated -+ public ItemStack getSpawnEgg0(org.bukkit.entity.EntityType type) { -+ if (type == null) { -+ return null; -+ } -+ String typeId = type.getKey().toString(); -+ net.minecraft.resources.ResourceLocation typeKey = ResourceLocation.parse(typeId); -+ net.minecraft.world.entity.EntityType nmsType = net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getValue(typeKey); -+ net.minecraft.world.item.SpawnEggItem eggItem = net.minecraft.world.item.SpawnEggItem.byId(nmsType); -+ return eggItem == null ? null : new net.minecraft.world.item.ItemStack(eggItem).asBukkitMirror(); -+ } -+ // Paper end - old getSpawnEgg API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -index 52a507ff2770bd46494e805956b4569f0d4d21ee..5a7aa491e0846ca8133bc4bb6e74b93cff85fb17 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -@@ -465,6 +465,15 @@ public class Commodore { - } - // Paper end - -+ // Paper start - ItemFactory#getSpawnEgg (paper had original method that returned ItemStack, upstream added identical but returned Material) -+ if (owner.equals("org/bukkit/inventory/ItemFactory") && name.equals("getSpawnEgg") && desc.equals("(Lorg/bukkit/entity/EntityType;)Lorg/bukkit/inventory/ItemStack;")) { -+ super.visitInsn(Opcodes.SWAP); // has 1 param, this moves the owner instance to the top for the checkcast -+ super.visitTypeInsn(Opcodes.CHECKCAST, runtimeCbPkgPrefix() + "inventory/CraftItemFactory"); -+ super.visitInsn(Opcodes.SWAP); // moves param back to the the top of stack -+ super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, runtimeCbPkgPrefix() + "inventory/CraftItemFactory", "getSpawnEgg0", desc, false); -+ return; -+ } -+ // Paper end - ItemFactory#getSpawnEgg - if (modern) { - if (owner.equals("org/bukkit/Material") || (instantiatedMethodType != null && instantiatedMethodType.getDescriptor().startsWith("(Lorg/bukkit/Material;)"))) { - switch (name) { diff --git a/patches/server/0580-Add-critical-damage-API.patch b/patches/server/0580-Add-critical-damage-API.patch new file mode 100644 index 0000000000..8f17aa1780 --- /dev/null +++ b/patches/server/0580-Add-critical-damage-API.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dodison +Date: Mon, 26 Jul 2021 17:32:36 +0200 +Subject: [PATCH] Add critical damage API + + +diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java +index c1d121d83591ca1b5bf9d9406c9622b4f24eafef..aee26dd78953ff43306aaa64161f5b9edcdd4b83 100644 +--- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java ++++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java +@@ -276,4 +276,18 @@ public class DamageSource { + public Holder typeHolder() { + return this.type; + } ++ ++ // Paper start - add critical damage API ++ private boolean critical; ++ public boolean isCritical() { ++ return this.critical; ++ } ++ public DamageSource critical() { ++ return this.critical(true); ++ } ++ public DamageSource critical(boolean critical) { ++ this.critical = critical; ++ return this; ++ } ++ // Paper end - add critical damage 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 13f21822d0eb1d167b9b71addb46c4f508301c8d..4e33c6c612939e6970d5984825115768ebb6a5ea 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -1261,6 +1261,7 @@ public abstract class Player extends LivingEntity { + + flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits + if (flag2) { ++ damagesource = damagesource.critical(true); // Paper start - critical damage API + f *= 1.5F; + } + +@@ -1320,7 +1321,7 @@ public abstract class Player extends LivingEntity { + float f7 = this.getEnchantedDamage(entityliving2, f6, damagesource) * f2; + + // CraftBukkit start - Only apply knockback if the damage hits +- if (!entityliving2.hurtServer((ServerLevel) this.level(), this.damageSources().playerAttack(this).sweep(), f7)) { ++ if (!entityliving2.hurtServer((ServerLevel) this.level(), this.damageSources().playerAttack(this).sweep().critical(flag2), f7)) { // Paper - add critical damage API + continue; + } + // CraftBukkit end +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 6637da7a1c17152e8fc5f0f12d8da55bab6070de..320ace815df1a76232df53d5ddeb3aef9b358d8e 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -465,6 +465,7 @@ public abstract class AbstractArrow extends Projectile { + entityliving.setLastHurtMob(entity); + } + ++ if (this.isCritArrow()) damagesource = damagesource.critical(); // Paper - add critical damage API + boolean flag = entity.getType() == EntityType.ENDERMAN; + int k = entity.getRemainingFireTicks(); + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 24f86724012bb8bcd6d24683a1c78ce66b42ca30..a5285a8952b2d99bfbb928b1bb31d3ddcf8ed57b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1078,7 +1078,7 @@ public class CraftEventFactory { + return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.BLOCK_EXPLOSION, bukkitDamageSource, modifiers, modifierFunctions, cancelled); + } + DamageCause damageCause = (damager.getBukkitEntity() instanceof org.bukkit.entity.TNTPrimed) ? DamageCause.BLOCK_EXPLOSION : DamageCause.ENTITY_EXPLOSION; +- return CraftEventFactory.callEntityDamageEvent(damager, entity, damageCause, bukkitDamageSource, modifiers, modifierFunctions, cancelled); ++ return CraftEventFactory.callEntityDamageEvent(damager, entity, damageCause, bukkitDamageSource, modifiers, modifierFunctions, cancelled, source.isCritical()); // Paper - add critical damage API + } else if (damager != null || source.getDirectEntity() != null) { + DamageCause cause = (source.isSweep()) ? DamageCause.ENTITY_SWEEP_ATTACK : DamageCause.ENTITY_ATTACK; + +@@ -1104,7 +1104,7 @@ public class CraftEventFactory { + cause = DamageCause.MAGIC; + } + +- return CraftEventFactory.callEntityDamageEvent(damager, entity, cause, bukkitDamageSource, modifiers, modifierFunctions, cancelled); ++ return CraftEventFactory.callEntityDamageEvent(damager, entity, cause, bukkitDamageSource, modifiers, modifierFunctions, cancelled, source.isCritical()); // Paper - add critical damage API + } else if (source.is(DamageTypes.FELL_OUT_OF_WORLD)) { + return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.VOID, bukkitDamageSource, modifiers, modifierFunctions, cancelled); + } else if (source.is(DamageTypes.LAVA)) { +@@ -1164,13 +1164,13 @@ public class CraftEventFactory { + cause = DamageCause.CUSTOM; + } + +- return CraftEventFactory.callEntityDamageEvent((Entity) null, entity, cause, bukkitDamageSource, modifiers, modifierFunctions, cancelled); ++ return CraftEventFactory.callEntityDamageEvent((Entity) null, entity, cause, bukkitDamageSource, modifiers, modifierFunctions, cancelled, source.isCritical()); // Paper - add critical damage API + } + +- private static EntityDamageEvent callEntityDamageEvent(Entity damager, Entity damagee, DamageCause cause, org.bukkit.damage.DamageSource bukkitDamageSource, Map modifiers, Map> modifierFunctions, boolean cancelled) { ++ private static EntityDamageEvent callEntityDamageEvent(Entity damager, Entity damagee, DamageCause cause, org.bukkit.damage.DamageSource bukkitDamageSource, Map modifiers, Map> modifierFunctions, boolean cancelled, boolean critical) { // Paper - add critical damage API + EntityDamageEvent event; + if (damager != null) { +- event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions); ++ event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions, critical); + } else { + event = new EntityDamageEvent(damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions); + } diff --git a/patches/server/0581-Add-critical-damage-API.patch b/patches/server/0581-Add-critical-damage-API.patch deleted file mode 100644 index a4fa089b63..0000000000 --- a/patches/server/0581-Add-critical-damage-API.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: dodison -Date: Mon, 26 Jul 2021 17:32:36 +0200 -Subject: [PATCH] Add critical damage API - - -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -index c1d121d83591ca1b5bf9d9406c9622b4f24eafef..aee26dd78953ff43306aaa64161f5b9edcdd4b83 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -@@ -276,4 +276,18 @@ public class DamageSource { - public Holder typeHolder() { - return this.type; - } -+ -+ // Paper start - add critical damage API -+ private boolean critical; -+ public boolean isCritical() { -+ return this.critical; -+ } -+ public DamageSource critical() { -+ return this.critical(true); -+ } -+ public DamageSource critical(boolean critical) { -+ this.critical = critical; -+ return this; -+ } -+ // Paper end - add critical damage 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 13f21822d0eb1d167b9b71addb46c4f508301c8d..4e33c6c612939e6970d5984825115768ebb6a5ea 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -1261,6 +1261,7 @@ public abstract class Player extends LivingEntity { - - flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits - if (flag2) { -+ damagesource = damagesource.critical(true); // Paper start - critical damage API - f *= 1.5F; - } - -@@ -1320,7 +1321,7 @@ public abstract class Player extends LivingEntity { - float f7 = this.getEnchantedDamage(entityliving2, f6, damagesource) * f2; - - // CraftBukkit start - Only apply knockback if the damage hits -- if (!entityliving2.hurtServer((ServerLevel) this.level(), this.damageSources().playerAttack(this).sweep(), f7)) { -+ if (!entityliving2.hurtServer((ServerLevel) this.level(), this.damageSources().playerAttack(this).sweep().critical(flag2), f7)) { // Paper - add critical damage API - continue; - } - // CraftBukkit end -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 52765e1b9f5a026e7108ff5a7d97681cdb2870e9..aab7d546317d93876ccd0e02c0631ccc7c8f9bf5 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -465,6 +465,7 @@ public abstract class AbstractArrow extends Projectile { - entityliving.setLastHurtMob(entity); - } - -+ if (this.isCritArrow()) damagesource = damagesource.critical(); // Paper - add critical damage API - boolean flag = entity.getType() == EntityType.ENDERMAN; - int k = entity.getRemainingFireTicks(); - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 24f86724012bb8bcd6d24683a1c78ce66b42ca30..a5285a8952b2d99bfbb928b1bb31d3ddcf8ed57b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1078,7 +1078,7 @@ public class CraftEventFactory { - return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.BLOCK_EXPLOSION, bukkitDamageSource, modifiers, modifierFunctions, cancelled); - } - DamageCause damageCause = (damager.getBukkitEntity() instanceof org.bukkit.entity.TNTPrimed) ? DamageCause.BLOCK_EXPLOSION : DamageCause.ENTITY_EXPLOSION; -- return CraftEventFactory.callEntityDamageEvent(damager, entity, damageCause, bukkitDamageSource, modifiers, modifierFunctions, cancelled); -+ return CraftEventFactory.callEntityDamageEvent(damager, entity, damageCause, bukkitDamageSource, modifiers, modifierFunctions, cancelled, source.isCritical()); // Paper - add critical damage API - } else if (damager != null || source.getDirectEntity() != null) { - DamageCause cause = (source.isSweep()) ? DamageCause.ENTITY_SWEEP_ATTACK : DamageCause.ENTITY_ATTACK; - -@@ -1104,7 +1104,7 @@ public class CraftEventFactory { - cause = DamageCause.MAGIC; - } - -- return CraftEventFactory.callEntityDamageEvent(damager, entity, cause, bukkitDamageSource, modifiers, modifierFunctions, cancelled); -+ return CraftEventFactory.callEntityDamageEvent(damager, entity, cause, bukkitDamageSource, modifiers, modifierFunctions, cancelled, source.isCritical()); // Paper - add critical damage API - } else if (source.is(DamageTypes.FELL_OUT_OF_WORLD)) { - return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.VOID, bukkitDamageSource, modifiers, modifierFunctions, cancelled); - } else if (source.is(DamageTypes.LAVA)) { -@@ -1164,13 +1164,13 @@ public class CraftEventFactory { - cause = DamageCause.CUSTOM; - } - -- return CraftEventFactory.callEntityDamageEvent((Entity) null, entity, cause, bukkitDamageSource, modifiers, modifierFunctions, cancelled); -+ return CraftEventFactory.callEntityDamageEvent((Entity) null, entity, cause, bukkitDamageSource, modifiers, modifierFunctions, cancelled, source.isCritical()); // Paper - add critical damage API - } - -- private static EntityDamageEvent callEntityDamageEvent(Entity damager, Entity damagee, DamageCause cause, org.bukkit.damage.DamageSource bukkitDamageSource, Map modifiers, Map> modifierFunctions, boolean cancelled) { -+ private static EntityDamageEvent callEntityDamageEvent(Entity damager, Entity damagee, DamageCause cause, org.bukkit.damage.DamageSource bukkitDamageSource, Map modifiers, Map> modifierFunctions, boolean cancelled, boolean critical) { // Paper - add critical damage API - EntityDamageEvent event; - if (damager != null) { -- event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions); -+ event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions, critical); - } else { - event = new EntityDamageEvent(damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions); - } diff --git a/patches/server/0581-Fix-issues-with-mob-conversion.patch b/patches/server/0581-Fix-issues-with-mob-conversion.patch new file mode 100644 index 0000000000..c286b73b30 --- /dev/null +++ b/patches/server/0581-Fix-issues-with-mob-conversion.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sun, 24 Oct 2021 20:29:45 -0700 +Subject: [PATCH] Fix issues with mob conversion + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java +index 6f6454bcec7e0d1cefbf818fc2fc6eb90adeec83..3972e2ed0554e2550519e994888e068df0a151e5 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java +@@ -94,12 +94,19 @@ public class Skeleton extends AbstractSkeleton { + } + + protected void doFreezeConversion() { +- this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), (entityskeletonstray) -> { ++ final Stray stray = this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), (entityskeletonstray) -> { // Paper - Fix issues with mob conversion; reset conversion time to prevent event spam + if (!this.isSilent()) { + this.level().levelEvent((Player) null, 1048, this.blockPosition(), 0); + } + +- }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.FROZEN, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.FROZEN); // CraftBukkit - add spawn and transform reasons ++ }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.FROZEN, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.FROZEN);// CraftBukkit - add spawn and transform reasons ++ ++ // Paper start - Fix issues with mob conversion; reset conversion time to prevent event spam ++ if (stray == null) { ++ this.conversionTime = 300; ++ } ++ // Paper end - Fix issues with mob conversion ++ + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java +index 34fff71edbdcefe87985f31cbf1ef282435ace06..92270912ef26924f611a1df7cb3d5b485b0a262d 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java +@@ -241,9 +241,15 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { + } + + private void finishConversion() { +- this.convertTo(EntityType.ZOGLIN, ConversionParams.single(this, true, false), (entityzoglin) -> { ++ net.minecraft.world.entity.Entity converted = this.convertTo(EntityType.ZOGLIN, ConversionParams.single(this, true, false), (entityzoglin) -> { + entityzoglin.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)); + }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED); // CraftBukkit - add spawn and transform reasons ++ ++ // Paper start - Fix issues with mob conversion; reset to prevent event spam ++ if (converted == null) { ++ this.timeInOverworld = 0; ++ } ++ // Paper end - Fix issues with mob conversion + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java +index e2075fb22596b6dc4dbbb9c20c91c63f0ddb7ba7..e3a8aa0ae0d1fa6f2b697e20464224f8b8c6b8ea 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java +@@ -100,9 +100,15 @@ public abstract class AbstractPiglin extends Monster { + } + + protected void finishConversion(ServerLevel world) { +- this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), (entitypigzombie) -> { ++ net.minecraft.world.entity.Entity converted = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), (entitypigzombie) -> { // Paper - Fix issues with mob conversion; reset to prevent event spam + entitypigzombie.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)); + }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED); // CraftBukkit - add spawn and transform reasons ++ ++ // Paper start - Fix issues with mob conversion; reset to prevent event spam ++ if (converted == null) { ++ this.timeInOverworld = 0; ++ } ++ // Paper end - Fix issues with mob conversion + } + + public boolean isAdult() { diff --git a/patches/server/0582-Add-hasCollision-methods-to-various-places.patch b/patches/server/0582-Add-hasCollision-methods-to-various-places.patch new file mode 100644 index 0000000000..421b0ba92e --- /dev/null +++ b/patches/server/0582-Add-hasCollision-methods-to-various-places.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Thu, 4 Nov 2021 11:50:40 -0700 +Subject: [PATCH] Add hasCollision methods to various places + +== AT == +public net.minecraft.world.level.block.state.BlockBehaviour hasCollision + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 9c8aac69f01db647e20d49d272ccc107a7edceaf..d5b495b5a3ca7f4411d1a700f7149042a16509f1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -457,6 +457,11 @@ public class CraftBlock implements Block { + public boolean isSolid() { + return this.getNMS().blocksMotion(); + } ++ ++ @Override ++ public boolean isCollidable() { ++ return getNMS().getBlock().hasCollision; ++ } + // Paper end + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +index 1002123cd0c6f57cecc4e80f5f21cc6ff5886d37..e96023b71845526383288917e8d7c5759a4c0e9b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +@@ -341,4 +341,11 @@ public class CraftBlockState implements BlockState { + public BlockState copy(Location location) { + return new CraftBlockState(this, location); + } ++ ++ // Paper start ++ @Override ++ public boolean isCollidable() { ++ return this.data.getBlock().hasCollision; ++ } ++ // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java +index 2d8a509446c0ed0d7358f10f67ef29c4df683696..785d3fe4929e008d4150f3ecab258fd5b6d7cdaf 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java +@@ -241,4 +241,11 @@ public class CraftBlockType implements BlockType.Typed, + return this.block.getDescriptionId(); + } + // Paper end - add Translatable ++ ++ // Paper start - hasCollision API ++ @Override ++ public boolean hasCollision() { ++ return this.block.hasCollision; ++ } ++ // Paper end - hasCollision API + } diff --git a/patches/server/0582-Fix-issues-with-mob-conversion.patch b/patches/server/0582-Fix-issues-with-mob-conversion.patch deleted file mode 100644 index c286b73b30..0000000000 --- a/patches/server/0582-Fix-issues-with-mob-conversion.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sun, 24 Oct 2021 20:29:45 -0700 -Subject: [PATCH] Fix issues with mob conversion - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -index 6f6454bcec7e0d1cefbf818fc2fc6eb90adeec83..3972e2ed0554e2550519e994888e068df0a151e5 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -@@ -94,12 +94,19 @@ public class Skeleton extends AbstractSkeleton { - } - - protected void doFreezeConversion() { -- this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), (entityskeletonstray) -> { -+ final Stray stray = this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), (entityskeletonstray) -> { // Paper - Fix issues with mob conversion; reset conversion time to prevent event spam - if (!this.isSilent()) { - this.level().levelEvent((Player) null, 1048, this.blockPosition(), 0); - } - -- }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.FROZEN, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.FROZEN); // CraftBukkit - add spawn and transform reasons -+ }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.FROZEN, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.FROZEN);// CraftBukkit - add spawn and transform reasons -+ -+ // Paper start - Fix issues with mob conversion; reset conversion time to prevent event spam -+ if (stray == null) { -+ this.conversionTime = 300; -+ } -+ // Paper end - Fix issues with mob conversion -+ - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index 34fff71edbdcefe87985f31cbf1ef282435ace06..92270912ef26924f611a1df7cb3d5b485b0a262d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -241,9 +241,15 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - } - - private void finishConversion() { -- this.convertTo(EntityType.ZOGLIN, ConversionParams.single(this, true, false), (entityzoglin) -> { -+ net.minecraft.world.entity.Entity converted = this.convertTo(EntityType.ZOGLIN, ConversionParams.single(this, true, false), (entityzoglin) -> { - entityzoglin.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)); - }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED); // CraftBukkit - add spawn and transform reasons -+ -+ // Paper start - Fix issues with mob conversion; reset to prevent event spam -+ if (converted == null) { -+ this.timeInOverworld = 0; -+ } -+ // Paper end - Fix issues with mob conversion - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java -index e2075fb22596b6dc4dbbb9c20c91c63f0ddb7ba7..e3a8aa0ae0d1fa6f2b697e20464224f8b8c6b8ea 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java -@@ -100,9 +100,15 @@ public abstract class AbstractPiglin extends Monster { - } - - protected void finishConversion(ServerLevel world) { -- this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), (entitypigzombie) -> { -+ net.minecraft.world.entity.Entity converted = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), (entitypigzombie) -> { // Paper - Fix issues with mob conversion; reset to prevent event spam - entitypigzombie.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)); - }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED); // CraftBukkit - add spawn and transform reasons -+ -+ // Paper start - Fix issues with mob conversion; reset to prevent event spam -+ if (converted == null) { -+ this.timeInOverworld = 0; -+ } -+ // Paper end - Fix issues with mob conversion - } - - public boolean isAdult() { diff --git a/patches/server/0583-Add-hasCollision-methods-to-various-places.patch b/patches/server/0583-Add-hasCollision-methods-to-various-places.patch deleted file mode 100644 index 421b0ba92e..0000000000 --- a/patches/server/0583-Add-hasCollision-methods-to-various-places.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 4 Nov 2021 11:50:40 -0700 -Subject: [PATCH] Add hasCollision methods to various places - -== AT == -public net.minecraft.world.level.block.state.BlockBehaviour hasCollision - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 9c8aac69f01db647e20d49d272ccc107a7edceaf..d5b495b5a3ca7f4411d1a700f7149042a16509f1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -457,6 +457,11 @@ public class CraftBlock implements Block { - public boolean isSolid() { - return this.getNMS().blocksMotion(); - } -+ -+ @Override -+ public boolean isCollidable() { -+ return getNMS().getBlock().hasCollision; -+ } - // Paper end - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -index 1002123cd0c6f57cecc4e80f5f21cc6ff5886d37..e96023b71845526383288917e8d7c5759a4c0e9b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -@@ -341,4 +341,11 @@ public class CraftBlockState implements BlockState { - public BlockState copy(Location location) { - return new CraftBlockState(this, location); - } -+ -+ // Paper start -+ @Override -+ public boolean isCollidable() { -+ return this.data.getBlock().hasCollision; -+ } -+ // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java -index 2d8a509446c0ed0d7358f10f67ef29c4df683696..785d3fe4929e008d4150f3ecab258fd5b6d7cdaf 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java -@@ -241,4 +241,11 @@ public class CraftBlockType implements BlockType.Typed, - return this.block.getDescriptionId(); - } - // Paper end - add Translatable -+ -+ // Paper start - hasCollision API -+ @Override -+ public boolean hasCollision() { -+ return this.block.hasCollision; -+ } -+ // Paper end - hasCollision API - } diff --git a/patches/server/0583-Goat-ram-API.patch b/patches/server/0583-Goat-ram-API.patch new file mode 100644 index 0000000000..21d6196f4c --- /dev/null +++ b/patches/server/0583-Goat-ram-API.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Seggan +Date: Thu, 5 Aug 2021 13:10:27 -0400 +Subject: [PATCH] Goat ram API + + +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 cccf0084d273eaded91abe249d39a843f11d351b..14e02f9b0169db8388c515a68315ad5cc3f13d22 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 +@@ -395,4 +395,15 @@ public class Goat extends Animal { + public static boolean checkGoatSpawnRules(EntityType entityType, LevelAccessor world, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random) { + return world.getBlockState(pos.below()).is(BlockTags.GOATS_SPAWNABLE_ON) && isBrightEnoughToSpawn(world, pos); + } ++ ++ // Paper start - Goat ram API ++ public void ram(net.minecraft.world.entity.LivingEntity entity) { ++ Brain brain = this.getBrain(); ++ brain.setMemory(MemoryModuleType.RAM_TARGET, entity.position()); ++ brain.eraseMemory(MemoryModuleType.RAM_COOLDOWN_TICKS); ++ brain.eraseMemory(MemoryModuleType.BREED_TARGET); ++ brain.eraseMemory(MemoryModuleType.TEMPTING_PLAYER); ++ brain.setActiveActivityIfPossible(net.minecraft.world.entity.schedule.Activity.RAM); ++ } ++ // Paper end - Goat ram API + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftGoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftGoat.java +index 65fcb36e849da6949c123a6f3672b485036f368e..2c21de478bff9cdf13ba46cd041831d54c11e924 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftGoat.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftGoat.java +@@ -48,4 +48,11 @@ public class CraftGoat extends CraftAnimals implements Goat { + public void setScreaming(boolean screaming) { + this.getHandle().setScreamingGoat(screaming); + } ++ ++ // Paper start - Goat ram API ++ @Override ++ public void ram(@org.jetbrains.annotations.NotNull org.bukkit.entity.LivingEntity entity) { ++ this.getHandle().ram(((CraftLivingEntity) entity).getHandle()); ++ } ++ // Paper end + } diff --git a/patches/server/0584-Add-API-for-resetting-a-single-score.patch b/patches/server/0584-Add-API-for-resetting-a-single-score.patch new file mode 100644 index 0000000000..b9dd1c2be3 --- /dev/null +++ b/patches/server/0584-Add-API-for-resetting-a-single-score.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: booky10 +Date: Fri, 5 Nov 2021 21:01:36 +0100 +Subject: [PATCH] Add API for resetting a single score + +It was only possible to reset all scores for a specific entry, instead of resetting only specific scores. + +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +index 29e24461e29e4cf3d31497198debcde18761ad73..ceb1a39c02c3cfa7632a0fdca414c7046888fcb1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +@@ -66,4 +66,12 @@ final class CraftScore implements Score { + public CraftScoreboard getScoreboard() { + return this.objective.getScoreboard(); + } ++ ++ // Paper start ++ @Override ++ public void resetScore() { ++ Scoreboard board = this.objective.checkState().board; ++ board.resetSinglePlayerScore(entry, this.objective.getHandle()); ++ } ++ // Paper end + } diff --git a/patches/server/0584-Goat-ram-API.patch b/patches/server/0584-Goat-ram-API.patch deleted file mode 100644 index 21d6196f4c..0000000000 --- a/patches/server/0584-Goat-ram-API.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Seggan -Date: Thu, 5 Aug 2021 13:10:27 -0400 -Subject: [PATCH] Goat ram API - - -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 cccf0084d273eaded91abe249d39a843f11d351b..14e02f9b0169db8388c515a68315ad5cc3f13d22 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 -@@ -395,4 +395,15 @@ public class Goat extends Animal { - public static boolean checkGoatSpawnRules(EntityType entityType, LevelAccessor world, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random) { - return world.getBlockState(pos.below()).is(BlockTags.GOATS_SPAWNABLE_ON) && isBrightEnoughToSpawn(world, pos); - } -+ -+ // Paper start - Goat ram API -+ public void ram(net.minecraft.world.entity.LivingEntity entity) { -+ Brain brain = this.getBrain(); -+ brain.setMemory(MemoryModuleType.RAM_TARGET, entity.position()); -+ brain.eraseMemory(MemoryModuleType.RAM_COOLDOWN_TICKS); -+ brain.eraseMemory(MemoryModuleType.BREED_TARGET); -+ brain.eraseMemory(MemoryModuleType.TEMPTING_PLAYER); -+ brain.setActiveActivityIfPossible(net.minecraft.world.entity.schedule.Activity.RAM); -+ } -+ // Paper end - Goat ram API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftGoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftGoat.java -index 65fcb36e849da6949c123a6f3672b485036f368e..2c21de478bff9cdf13ba46cd041831d54c11e924 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftGoat.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftGoat.java -@@ -48,4 +48,11 @@ public class CraftGoat extends CraftAnimals implements Goat { - public void setScreaming(boolean screaming) { - this.getHandle().setScreamingGoat(screaming); - } -+ -+ // Paper start - Goat ram API -+ @Override -+ public void ram(@org.jetbrains.annotations.NotNull org.bukkit.entity.LivingEntity entity) { -+ this.getHandle().ram(((CraftLivingEntity) entity).getHandle()); -+ } -+ // Paper end - } diff --git a/patches/server/0585-Add-API-for-resetting-a-single-score.patch b/patches/server/0585-Add-API-for-resetting-a-single-score.patch deleted file mode 100644 index b9dd1c2be3..0000000000 --- a/patches/server/0585-Add-API-for-resetting-a-single-score.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: booky10 -Date: Fri, 5 Nov 2021 21:01:36 +0100 -Subject: [PATCH] Add API for resetting a single score - -It was only possible to reset all scores for a specific entry, instead of resetting only specific scores. - -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java -index 29e24461e29e4cf3d31497198debcde18761ad73..ceb1a39c02c3cfa7632a0fdca414c7046888fcb1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java -@@ -66,4 +66,12 @@ final class CraftScore implements Score { - public CraftScoreboard getScoreboard() { - return this.objective.getScoreboard(); - } -+ -+ // Paper start -+ @Override -+ public void resetScore() { -+ Scoreboard board = this.objective.checkState().board; -+ board.resetSinglePlayerScore(entry, this.objective.getHandle()); -+ } -+ // Paper end - } diff --git a/patches/server/0585-Add-Raw-Byte-Entity-Serialization.patch b/patches/server/0585-Add-Raw-Byte-Entity-Serialization.patch new file mode 100644 index 0000000000..efff5ebd8c --- /dev/null +++ b/patches/server/0585-Add-Raw-Byte-Entity-Serialization.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sun, 24 Oct 2021 16:20:31 -0400 +Subject: [PATCH] Add Raw Byte Entity Serialization + +== AT == +public net.minecraft.world.entity.Entity setLevel(Lnet/minecraft/world/level/Level;)V + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 2a9be5b06f2f9db8f1ed2061c4fc3f94600e266a..fe1a30e4c73dbecbd44187dbdef0d98b7613e524 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2284,6 +2284,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + } + ++ // Paper start - Entity serialization api ++ public boolean serializeEntity(CompoundTag compound) { ++ List pass = new java.util.ArrayList<>(this.getPassengers()); ++ this.passengers = ImmutableList.of(); ++ boolean result = save(compound); ++ this.passengers = ImmutableList.copyOf(pass); ++ return result; ++ } ++ // Paper end - Entity serialization api + public boolean save(CompoundTag nbt) { + return this.isPassenger() ? false : this.saveAsPassenger(nbt); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 888a75423ac90ca85308eeb6d67bac5348bf31e0..b13c947d2cfe085017b30cb0f8340dd64f338914 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1083,6 +1083,18 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + } + // Paper end - tracked players API + ++ // Paper start - raw entity serialization API ++ @Override ++ public boolean spawnAt(Location location, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { ++ Preconditions.checkNotNull(location, "location cannot be null"); ++ Preconditions.checkNotNull(reason, "reason cannot be null"); ++ this.entity.setLevel(((CraftWorld) location.getWorld()).getHandle()); ++ this.entity.setPos(location.getX(), location.getY(), location.getZ()); ++ this.entity.setRot(location.getYaw(), location.getPitch()); ++ return !this.entity.valid && this.entity.level().addFreshEntity(this.entity, reason); ++ } ++ // Paper end - raw entity serialization API ++ + // Paper start - missing entity api + @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 6f780b76ebadb6155195b93f3e6d382141eb0bcc..d7698f8ae59195458148397406a104224676b76e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -510,7 +510,33 @@ public final class CraftMagicNumbers implements UnsafeValues { + return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow()); + } + +- private byte[] serializeNbtToBytes(CompoundTag compound) { ++ @Override ++ public byte[] serializeEntity(org.bukkit.entity.Entity entity) { ++ Preconditions.checkNotNull(entity, "null cannot be serialized"); ++ Preconditions.checkArgument(entity instanceof org.bukkit.craftbukkit.entity.CraftEntity, "only CraftEntities can be serialized"); ++ ++ net.minecraft.nbt.CompoundTag compound = new net.minecraft.nbt.CompoundTag(); ++ ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().serializeEntity(compound); ++ return serializeNbtToBytes(compound); ++ } ++ ++ @Override ++ public org.bukkit.entity.Entity deserializeEntity(byte[] data, org.bukkit.World world, boolean preserveUUID) { ++ Preconditions.checkNotNull(data, "null cannot be deserialized"); ++ Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing"); ++ ++ net.minecraft.nbt.CompoundTag compound = deserializeNbtFromBytes(data); ++ int dataVersion = compound.getInt("DataVersion"); ++ compound = (net.minecraft.nbt.CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ENTITY, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, this.getDataVersion()).getValue(); ++ if (!preserveUUID) { ++ // Generate a new UUID so we don't have to worry about deserializing the same entity twice ++ compound.remove("UUID"); ++ } ++ return net.minecraft.world.entity.EntityType.create(compound, ((org.bukkit.craftbukkit.CraftWorld) world).getHandle(), net.minecraft.world.entity.EntitySpawnReason.LOAD) ++ .orElseThrow(() -> new IllegalArgumentException("An ID was not found for the data. Did you downgrade?")).getBukkitEntity(); ++ } ++ ++ private byte[] serializeNbtToBytes(net.minecraft.nbt.CompoundTag compound) { + compound.putInt("DataVersion", getDataVersion()); + java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream(); + try { diff --git a/patches/server/0586-Add-Raw-Byte-Entity-Serialization.patch b/patches/server/0586-Add-Raw-Byte-Entity-Serialization.patch deleted file mode 100644 index 270801e16a..0000000000 --- a/patches/server/0586-Add-Raw-Byte-Entity-Serialization.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sun, 24 Oct 2021 16:20:31 -0400 -Subject: [PATCH] Add Raw Byte Entity Serialization - -== AT == -public net.minecraft.world.entity.Entity setLevel(Lnet/minecraft/world/level/Level;)V - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index dbea0da4b2c0dda744a1995c779049d3d63351cb..ca0353307f6a1d937ec9663a19489135b9844963 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2284,6 +2284,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - } - -+ // Paper start - Entity serialization api -+ public boolean serializeEntity(CompoundTag compound) { -+ List pass = new java.util.ArrayList<>(this.getPassengers()); -+ this.passengers = ImmutableList.of(); -+ boolean result = save(compound); -+ this.passengers = ImmutableList.copyOf(pass); -+ return result; -+ } -+ // Paper end - Entity serialization api - public boolean save(CompoundTag nbt) { - return this.isPassenger() ? false : this.saveAsPassenger(nbt); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 888a75423ac90ca85308eeb6d67bac5348bf31e0..b13c947d2cfe085017b30cb0f8340dd64f338914 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1083,6 +1083,18 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - } - // Paper end - tracked players API - -+ // Paper start - raw entity serialization API -+ @Override -+ public boolean spawnAt(Location location, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { -+ Preconditions.checkNotNull(location, "location cannot be null"); -+ Preconditions.checkNotNull(reason, "reason cannot be null"); -+ this.entity.setLevel(((CraftWorld) location.getWorld()).getHandle()); -+ this.entity.setPos(location.getX(), location.getY(), location.getZ()); -+ this.entity.setRot(location.getYaw(), location.getPitch()); -+ return !this.entity.valid && this.entity.level().addFreshEntity(this.entity, reason); -+ } -+ // Paper end - raw entity serialization API -+ - // Paper start - missing entity api - @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 6f780b76ebadb6155195b93f3e6d382141eb0bcc..d7698f8ae59195458148397406a104224676b76e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -510,7 +510,33 @@ public final class CraftMagicNumbers implements UnsafeValues { - return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow()); - } - -- private byte[] serializeNbtToBytes(CompoundTag compound) { -+ @Override -+ public byte[] serializeEntity(org.bukkit.entity.Entity entity) { -+ Preconditions.checkNotNull(entity, "null cannot be serialized"); -+ Preconditions.checkArgument(entity instanceof org.bukkit.craftbukkit.entity.CraftEntity, "only CraftEntities can be serialized"); -+ -+ net.minecraft.nbt.CompoundTag compound = new net.minecraft.nbt.CompoundTag(); -+ ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().serializeEntity(compound); -+ return serializeNbtToBytes(compound); -+ } -+ -+ @Override -+ public org.bukkit.entity.Entity deserializeEntity(byte[] data, org.bukkit.World world, boolean preserveUUID) { -+ Preconditions.checkNotNull(data, "null cannot be deserialized"); -+ Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing"); -+ -+ net.minecraft.nbt.CompoundTag compound = deserializeNbtFromBytes(data); -+ int dataVersion = compound.getInt("DataVersion"); -+ compound = (net.minecraft.nbt.CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ENTITY, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, this.getDataVersion()).getValue(); -+ if (!preserveUUID) { -+ // Generate a new UUID so we don't have to worry about deserializing the same entity twice -+ compound.remove("UUID"); -+ } -+ return net.minecraft.world.entity.EntityType.create(compound, ((org.bukkit.craftbukkit.CraftWorld) world).getHandle(), net.minecraft.world.entity.EntitySpawnReason.LOAD) -+ .orElseThrow(() -> new IllegalArgumentException("An ID was not found for the data. Did you downgrade?")).getBukkitEntity(); -+ } -+ -+ private byte[] serializeNbtToBytes(net.minecraft.nbt.CompoundTag compound) { - compound.putInt("DataVersion", getDataVersion()); - java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream(); - try { diff --git a/patches/server/0586-Vanilla-command-permission-fixes.patch b/patches/server/0586-Vanilla-command-permission-fixes.patch new file mode 100644 index 0000000000..90d31ae40c --- /dev/null +++ b/patches/server/0586-Vanilla-command-permission-fixes.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Wed, 25 Aug 2021 13:19:53 -0700 +Subject: [PATCH] Vanilla command permission fixes + +Fixes permission checks for vanilla commands which don't have a +requirement, as well as for namespaced vanilla commands. + +== AT == +public-f com.mojang.brigadier.tree.CommandNode requirement + +diff --git a/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java b/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java +index 899008b2980d13f1be6280cd8cb959c53a29bebf..d5f7da3502575f6847f3c22ab0e942848a7c6031 100644 +--- a/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java ++++ b/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java +@@ -14,9 +14,17 @@ import java.util.Collections; + import java.util.function.Predicate; + + public abstract class ArgumentBuilder> { ++ // Paper start - Vanilla command permission fixes ++ private static final Predicate DEFAULT_REQUIREMENT = s -> true; ++ ++ @SuppressWarnings("unchecked") ++ public static Predicate defaultRequirement() { ++ return (Predicate) DEFAULT_REQUIREMENT; ++ } ++ // Paper end - Vanilla command permission fixes + private final RootCommandNode arguments = new RootCommandNode<>(); + private Command command; +- private Predicate requirement = s -> true; ++ private Predicate requirement = defaultRequirement(); // Paper - Vanilla command permission fixes + private CommandNode target; + private RedirectModifier modifier = null; + private boolean forks; +diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java +index d602c713696e23ba6a2d542b2e9e2cce46d79a66..800d1756db8c27b7d129a90addc125c4fc81e134 100644 +--- a/src/main/java/net/minecraft/commands/Commands.java ++++ b/src/main/java/net/minecraft/commands/Commands.java +@@ -261,6 +261,13 @@ public class Commands { + PublishCommand.register(this.dispatcher); + } + ++ // Paper start - Vanilla command permission fixes ++ for (final CommandNode node : this.dispatcher.getRoot().getChildren()) { ++ if (node.getRequirement() == com.mojang.brigadier.builder.ArgumentBuilder.defaultRequirement()) { ++ node.requirement = stack -> stack.source == CommandSource.NULL || stack.getBukkitSender().hasPermission(org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(node)); ++ } ++ } ++ // Paper end - Vanilla command permission fixes + // CraftBukkit start + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +index 9b453830e4b949d67c2a01adc309ddc6ad019be1..35b05f9321ddbbbdf62f4bf726b58cf1205f0cfb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +@@ -91,7 +91,21 @@ public final class VanillaCommandWrapper extends BukkitCommand { + } + + public static String getPermission(CommandNode vanillaCommand) { +- return "minecraft.command." + ((vanillaCommand.getRedirect() == null) ? vanillaCommand.getName() : vanillaCommand.getRedirect().getName()); ++ // Paper start - Vanilla command permission fixes ++ while (vanillaCommand.getRedirect() != null) { ++ vanillaCommand = vanillaCommand.getRedirect(); ++ } ++ final String commandName = vanillaCommand.getName(); ++ return "minecraft.command." + stripDefaultNamespace(commandName); ++ } ++ ++ private static String stripDefaultNamespace(final String maybeNamespaced) { ++ final String prefix = "minecraft:"; ++ if (maybeNamespaced.startsWith(prefix)) { ++ return maybeNamespaced.substring(prefix.length()); ++ } ++ return maybeNamespaced; ++ // Paper end - Vanilla command permission fixes + } + + private String toDispatcher(String[] args, String name) { diff --git a/patches/server/0587-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch b/patches/server/0587-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch new file mode 100644 index 0000000000..9cf58cf3c8 --- /dev/null +++ b/patches/server/0587-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Thu, 11 Mar 2021 03:03:32 -0800 +Subject: [PATCH] Do not run close logic for inventories on chunk unload + +Still call the event and change the active container though. We +want to avoid close logic because it's possible to load the +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 75d0143556dad6e830d3defdd9afecfd7587cdfa..1301622961ffdcfcccc9658a0e4498bc04ad93f5 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1245,9 +1245,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) { ++ // Paper start - this area looks like it can load chunks, change the behavior ++ // chests for example can apply physics to the world ++ // so instead we just change the active container and call the event + for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((net.minecraft.world.Container) tileentity).getViewers())) { +- h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason ++ ((org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason + } ++ // Paper end - this area looks like it can load chunks, change the behavior + } + } + // Spigot End +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 2392b30ef6cc2050be28f6dbd1d922227ab4a490..0401e274a600b87c4c983a90819a17c9dfbd7172 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1966,6 +1966,18 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); + this.doCloseContainer(); + } ++ // Paper start - special close for unloaded inventory ++ @Override ++ public void closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { ++ // copied from above ++ CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit ++ // Paper end ++ // copied from below ++ this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); ++ this.containerMenu = this.inventoryMenu; ++ // do not run close logic ++ } ++ // Paper end - special close for unloaded inventory + + @Override + public void doCloseContainer() { +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 4e33c6c612939e6970d5984825115768ebb6a5ea..81e3072ac80623db47ddc0b9c52e0e56dab9e10e 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -547,6 +547,11 @@ public abstract class Player extends LivingEntity { + this.containerMenu = this.inventoryMenu; + } + // Paper end - Inventory close reason ++ // Paper start - special close for unloaded inventory ++ public void closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { ++ this.containerMenu = this.inventoryMenu; ++ } ++ // Paper end - special close for unloaded inventory + + public void closeContainer() { + this.containerMenu = this.inventoryMenu; diff --git a/patches/server/0587-Vanilla-command-permission-fixes.patch b/patches/server/0587-Vanilla-command-permission-fixes.patch deleted file mode 100644 index 90d31ae40c..0000000000 --- a/patches/server/0587-Vanilla-command-permission-fixes.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Wed, 25 Aug 2021 13:19:53 -0700 -Subject: [PATCH] Vanilla command permission fixes - -Fixes permission checks for vanilla commands which don't have a -requirement, as well as for namespaced vanilla commands. - -== AT == -public-f com.mojang.brigadier.tree.CommandNode requirement - -diff --git a/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java b/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java -index 899008b2980d13f1be6280cd8cb959c53a29bebf..d5f7da3502575f6847f3c22ab0e942848a7c6031 100644 ---- a/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java -+++ b/src/main/java/com/mojang/brigadier/builder/ArgumentBuilder.java -@@ -14,9 +14,17 @@ import java.util.Collections; - import java.util.function.Predicate; - - public abstract class ArgumentBuilder> { -+ // Paper start - Vanilla command permission fixes -+ private static final Predicate DEFAULT_REQUIREMENT = s -> true; -+ -+ @SuppressWarnings("unchecked") -+ public static Predicate defaultRequirement() { -+ return (Predicate) DEFAULT_REQUIREMENT; -+ } -+ // Paper end - Vanilla command permission fixes - private final RootCommandNode arguments = new RootCommandNode<>(); - private Command command; -- private Predicate requirement = s -> true; -+ private Predicate requirement = defaultRequirement(); // Paper - Vanilla command permission fixes - private CommandNode target; - private RedirectModifier modifier = null; - private boolean forks; -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index d602c713696e23ba6a2d542b2e9e2cce46d79a66..800d1756db8c27b7d129a90addc125c4fc81e134 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -261,6 +261,13 @@ public class Commands { - PublishCommand.register(this.dispatcher); - } - -+ // Paper start - Vanilla command permission fixes -+ for (final CommandNode node : this.dispatcher.getRoot().getChildren()) { -+ if (node.getRequirement() == com.mojang.brigadier.builder.ArgumentBuilder.defaultRequirement()) { -+ node.requirement = stack -> stack.source == CommandSource.NULL || stack.getBukkitSender().hasPermission(org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(node)); -+ } -+ } -+ // Paper end - Vanilla command permission fixes - // CraftBukkit start - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java -index 9b453830e4b949d67c2a01adc309ddc6ad019be1..35b05f9321ddbbbdf62f4bf726b58cf1205f0cfb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java -@@ -91,7 +91,21 @@ public final class VanillaCommandWrapper extends BukkitCommand { - } - - public static String getPermission(CommandNode vanillaCommand) { -- return "minecraft.command." + ((vanillaCommand.getRedirect() == null) ? vanillaCommand.getName() : vanillaCommand.getRedirect().getName()); -+ // Paper start - Vanilla command permission fixes -+ while (vanillaCommand.getRedirect() != null) { -+ vanillaCommand = vanillaCommand.getRedirect(); -+ } -+ final String commandName = vanillaCommand.getName(); -+ return "minecraft.command." + stripDefaultNamespace(commandName); -+ } -+ -+ private static String stripDefaultNamespace(final String maybeNamespaced) { -+ final String prefix = "minecraft:"; -+ if (maybeNamespaced.startsWith(prefix)) { -+ return maybeNamespaced.substring(prefix.length()); -+ } -+ return maybeNamespaced; -+ // Paper end - Vanilla command permission fixes - } - - private String toDispatcher(String[] args, String name) { diff --git a/patches/server/0588-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch b/patches/server/0588-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch deleted file mode 100644 index f403613911..0000000000 --- a/patches/server/0588-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Thu, 11 Mar 2021 03:03:32 -0800 -Subject: [PATCH] Do not run close logic for inventories on chunk unload - -Still call the event and change the active container though. We -want to avoid close logic because it's possible to load the -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 e6ff03143b3639f375323393814b1256b98687ad..2ac09e8eece6ff772c94bb1efd01cc1c45194435 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1245,9 +1245,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) { -+ // Paper start - this area looks like it can load chunks, change the behavior -+ // chests for example can apply physics to the world -+ // so instead we just change the active container and call the event - for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((net.minecraft.world.Container) tileentity).getViewers())) { -- h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason -+ ((org.bukkit.craftbukkit.entity.CraftHumanEntity) h).getHandle().closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason - } -+ // Paper end - this area looks like it can load chunks, change the behavior - } - } - // Spigot End -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index f2cc608d2cf040be2912b604f0d6cab21e33ded0..215be207e29254312bb85f259a684a7de6876aa9 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1966,6 +1966,18 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { - this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); - this.doCloseContainer(); - } -+ // Paper start - special close for unloaded inventory -+ @Override -+ public void closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { -+ // copied from above -+ CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit -+ // Paper end -+ // copied from below -+ this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); -+ this.containerMenu = this.inventoryMenu; -+ // do not run close logic -+ } -+ // Paper end - special close for unloaded inventory - - @Override - public void doCloseContainer() { -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 4e33c6c612939e6970d5984825115768ebb6a5ea..81e3072ac80623db47ddc0b9c52e0e56dab9e10e 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -547,6 +547,11 @@ public abstract class Player extends LivingEntity { - this.containerMenu = this.inventoryMenu; - } - // Paper end - Inventory close reason -+ // Paper start - special close for unloaded inventory -+ public void closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { -+ this.containerMenu = this.inventoryMenu; -+ } -+ // Paper end - special close for unloaded inventory - - public void closeContainer() { - this.containerMenu = this.inventoryMenu; diff --git a/patches/server/0588-Fix-GameProfileCache-concurrency.patch b/patches/server/0588-Fix-GameProfileCache-concurrency.patch new file mode 100644 index 0000000000..6cb7e5235f --- /dev/null +++ b/patches/server/0588-Fix-GameProfileCache-concurrency.patch @@ -0,0 +1,126 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sat, 11 Jul 2020 05:09:28 -0700 +Subject: [PATCH] Fix GameProfileCache concurrency + +Separate lookup and state access locks prevent lookups +from stalling simple state access/write calls + +diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java +index 774d81c702edb76a2f6184d4dc53687de6734a79..34b4166adfae8ff7d1eb73d56a72931b005330a7 100644 +--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java ++++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java +@@ -60,6 +60,11 @@ public class GameProfileCache { + @Nullable + private Executor executor; + ++ // Paper start - Fix GameProfileCache concurrency ++ protected final java.util.concurrent.locks.ReentrantLock stateLock = new java.util.concurrent.locks.ReentrantLock(); ++ protected final java.util.concurrent.locks.ReentrantLock lookupLock = new java.util.concurrent.locks.ReentrantLock(); ++ // Paper end - Fix GameProfileCache concurrency ++ + public GameProfileCache(GameProfileRepository profileRepository, File cacheFile) { + this.profileRepository = profileRepository; + this.file = cacheFile; +@@ -67,11 +72,13 @@ public class GameProfileCache { + } + + private void safeAdd(GameProfileCache.GameProfileInfo entry) { ++ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency + GameProfile gameprofile = entry.getProfile(); + + entry.setLastAccess(this.getNextOperation()); + this.profilesByName.put(gameprofile.getName().toLowerCase(Locale.ROOT), entry); + this.profilesByUUID.put(gameprofile.getId(), entry); ++ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency + } + + private static Optional lookupGameProfile(GameProfileRepository repository, String name) { +@@ -128,17 +135,20 @@ public class GameProfileCache { + + // Paper start + public @Nullable GameProfile getProfileIfCached(String name) { ++ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency + GameProfileCache.GameProfileInfo entry = this.profilesByName.get(name.toLowerCase(Locale.ROOT)); + if (entry == null) { + return null; + } + entry.setLastAccess(this.getNextOperation()); + return entry.getProfile(); ++ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency + } + // Paper end + + public Optional get(String name) { + String s1 = name.toLowerCase(Locale.ROOT); ++ boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency + GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByName.get(s1); + boolean flag = false; + +@@ -154,8 +164,12 @@ public class GameProfileCache { + if (usercache_usercacheentry != null) { + usercache_usercacheentry.setLastAccess(this.getNextOperation()); + optional = Optional.of(usercache_usercacheentry.getProfile()); ++ stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency + } else { ++ stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency ++ try { this.lookupLock.lock(); // Paper - Fix GameProfileCache concurrency + optional = GameProfileCache.lookupGameProfile(this.profileRepository, name); // CraftBukkit - use correct case for offline players ++ } finally { this.lookupLock.unlock(); } // Paper - Fix GameProfileCache concurrency + if (optional.isPresent()) { + this.add((GameProfile) optional.get()); + flag = false; +@@ -167,6 +181,7 @@ public class GameProfileCache { + } + + return optional; ++ } finally { if (stateLocked) { this.stateLock.unlock(); } } // Paper - Fix GameProfileCache concurrency + } + + public CompletableFuture> getAsync(String username) { +@@ -191,6 +206,7 @@ public class GameProfileCache { + } + + public Optional get(UUID uuid) { ++ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency + GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByUUID.get(uuid); + + if (usercache_usercacheentry == null) { +@@ -199,6 +215,7 @@ public class GameProfileCache { + usercache_usercacheentry.setLastAccess(this.getNextOperation()); + return Optional.of(usercache_usercacheentry.getProfile()); + } ++ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency + } + + public void setExecutor(Executor executor) { +@@ -279,7 +296,7 @@ public class GameProfileCache { + JsonArray jsonarray = new JsonArray(); + DateFormat dateformat = GameProfileCache.createDateFormat(); + +- this.getTopMRUProfiles(org.spigotmc.SpigotConfig.userCacheCap).forEach((usercache_usercacheentry) -> { // Spigot ++ this.listTopMRUProfiles(org.spigotmc.SpigotConfig.userCacheCap).forEach((usercache_usercacheentry) -> { // Spigot // Paper - Fix GameProfileCache concurrency + jsonarray.add(GameProfileCache.writeGameProfile(usercache_usercacheentry, dateformat)); + }); + String s = this.gson.toJson(jsonarray); +@@ -320,8 +337,19 @@ public class GameProfileCache { + } + + private Stream getTopMRUProfiles(int limit) { +- return ImmutableList.copyOf(this.profilesByUUID.values()).stream().sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed()).limit((long) limit); ++ // Paper start - Fix GameProfileCache concurrency ++ return this.listTopMRUProfiles(limit).stream(); ++ } ++ ++ private List listTopMRUProfiles(int limit) { ++ try { ++ this.stateLock.lock(); ++ return this.profilesByUUID.values().stream().sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed()).limit(limit).toList(); ++ } finally { ++ this.stateLock.unlock(); ++ } + } ++ // Paper end - Fix GameProfileCache concurrency + + private static JsonElement writeGameProfile(GameProfileCache.GameProfileInfo entry, DateFormat dateFormat) { + JsonObject jsonobject = new JsonObject(); diff --git a/patches/server/0589-Fix-GameProfileCache-concurrency.patch b/patches/server/0589-Fix-GameProfileCache-concurrency.patch deleted file mode 100644 index 6cb7e5235f..0000000000 --- a/patches/server/0589-Fix-GameProfileCache-concurrency.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sat, 11 Jul 2020 05:09:28 -0700 -Subject: [PATCH] Fix GameProfileCache concurrency - -Separate lookup and state access locks prevent lookups -from stalling simple state access/write calls - -diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java -index 774d81c702edb76a2f6184d4dc53687de6734a79..34b4166adfae8ff7d1eb73d56a72931b005330a7 100644 ---- a/src/main/java/net/minecraft/server/players/GameProfileCache.java -+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java -@@ -60,6 +60,11 @@ public class GameProfileCache { - @Nullable - private Executor executor; - -+ // Paper start - Fix GameProfileCache concurrency -+ protected final java.util.concurrent.locks.ReentrantLock stateLock = new java.util.concurrent.locks.ReentrantLock(); -+ protected final java.util.concurrent.locks.ReentrantLock lookupLock = new java.util.concurrent.locks.ReentrantLock(); -+ // Paper end - Fix GameProfileCache concurrency -+ - public GameProfileCache(GameProfileRepository profileRepository, File cacheFile) { - this.profileRepository = profileRepository; - this.file = cacheFile; -@@ -67,11 +72,13 @@ public class GameProfileCache { - } - - private void safeAdd(GameProfileCache.GameProfileInfo entry) { -+ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency - GameProfile gameprofile = entry.getProfile(); - - entry.setLastAccess(this.getNextOperation()); - this.profilesByName.put(gameprofile.getName().toLowerCase(Locale.ROOT), entry); - this.profilesByUUID.put(gameprofile.getId(), entry); -+ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency - } - - private static Optional lookupGameProfile(GameProfileRepository repository, String name) { -@@ -128,17 +135,20 @@ public class GameProfileCache { - - // Paper start - public @Nullable GameProfile getProfileIfCached(String name) { -+ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency - GameProfileCache.GameProfileInfo entry = this.profilesByName.get(name.toLowerCase(Locale.ROOT)); - if (entry == null) { - return null; - } - entry.setLastAccess(this.getNextOperation()); - return entry.getProfile(); -+ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency - } - // Paper end - - public Optional get(String name) { - String s1 = name.toLowerCase(Locale.ROOT); -+ boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency - GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByName.get(s1); - boolean flag = false; - -@@ -154,8 +164,12 @@ public class GameProfileCache { - if (usercache_usercacheentry != null) { - usercache_usercacheentry.setLastAccess(this.getNextOperation()); - optional = Optional.of(usercache_usercacheentry.getProfile()); -+ stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency - } else { -+ stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency -+ try { this.lookupLock.lock(); // Paper - Fix GameProfileCache concurrency - optional = GameProfileCache.lookupGameProfile(this.profileRepository, name); // CraftBukkit - use correct case for offline players -+ } finally { this.lookupLock.unlock(); } // Paper - Fix GameProfileCache concurrency - if (optional.isPresent()) { - this.add((GameProfile) optional.get()); - flag = false; -@@ -167,6 +181,7 @@ public class GameProfileCache { - } - - return optional; -+ } finally { if (stateLocked) { this.stateLock.unlock(); } } // Paper - Fix GameProfileCache concurrency - } - - public CompletableFuture> getAsync(String username) { -@@ -191,6 +206,7 @@ public class GameProfileCache { - } - - public Optional get(UUID uuid) { -+ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency - GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByUUID.get(uuid); - - if (usercache_usercacheentry == null) { -@@ -199,6 +215,7 @@ public class GameProfileCache { - usercache_usercacheentry.setLastAccess(this.getNextOperation()); - return Optional.of(usercache_usercacheentry.getProfile()); - } -+ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency - } - - public void setExecutor(Executor executor) { -@@ -279,7 +296,7 @@ public class GameProfileCache { - JsonArray jsonarray = new JsonArray(); - DateFormat dateformat = GameProfileCache.createDateFormat(); - -- this.getTopMRUProfiles(org.spigotmc.SpigotConfig.userCacheCap).forEach((usercache_usercacheentry) -> { // Spigot -+ this.listTopMRUProfiles(org.spigotmc.SpigotConfig.userCacheCap).forEach((usercache_usercacheentry) -> { // Spigot // Paper - Fix GameProfileCache concurrency - jsonarray.add(GameProfileCache.writeGameProfile(usercache_usercacheentry, dateformat)); - }); - String s = this.gson.toJson(jsonarray); -@@ -320,8 +337,19 @@ public class GameProfileCache { - } - - private Stream getTopMRUProfiles(int limit) { -- return ImmutableList.copyOf(this.profilesByUUID.values()).stream().sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed()).limit((long) limit); -+ // Paper start - Fix GameProfileCache concurrency -+ return this.listTopMRUProfiles(limit).stream(); -+ } -+ -+ private List listTopMRUProfiles(int limit) { -+ try { -+ this.stateLock.lock(); -+ return this.profilesByUUID.values().stream().sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed()).limit(limit).toList(); -+ } finally { -+ this.stateLock.unlock(); -+ } - } -+ // Paper end - Fix GameProfileCache concurrency - - private static JsonElement writeGameProfile(GameProfileCache.GameProfileInfo entry, DateFormat dateFormat) { - JsonObject jsonobject = new JsonObject(); diff --git a/patches/server/0589-Improve-and-expand-AsyncCatcher.patch b/patches/server/0589-Improve-and-expand-AsyncCatcher.patch new file mode 100644 index 0000000000..3214e81ee8 --- /dev/null +++ b/patches/server/0589-Improve-and-expand-AsyncCatcher.patch @@ -0,0 +1,227 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Wed, 25 Aug 2021 20:17:12 -0700 +Subject: [PATCH] Improve and expand AsyncCatcher + +Log when the async catcher is tripped + The chunk system can swallow the exception given it's all + built with completablefuture, so ensure it is at least printed. + +Add/move several async catchers + +Async catch modifications to critical entity state + These used to be here from Spigot, but were dropped with 1.17. + Now in 1.17, this state is _even more_ critical than it was before, + so these must exist to catch stupid plugins. + +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 b9eb462cf7603fb4afe365f6f094c784a5ee1137..740363cfeb7808994c7e3824163af7af7862fb15 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1651,6 +1651,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + + public void internalTeleport(PositionMoveRotation positionmoverotation, Set set) { ++ org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper + // Paper start - Prevent teleporting dead entities + 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 7ee81d5891d9d18566012cd72a516870f529628e..a5d3e5b402ca0a2e806a783304d43eac9dc142ad 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -1143,7 +1143,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) { +- org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot ++ // org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot // Paper - move to API + if (this.isTickingEffects) { + this.effectsToProcess.add(new ProcessableEffect(mobeffect, cause)); + return true; +diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +index 4eb0b0969325f39a7ae65492cccd482515a50142..5aa74c00a61282830d82359eae2b114e2a48b6d9 100644 +--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java ++++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +@@ -78,6 +78,7 @@ public class PersistentEntitySectionManager implements A + } + + private boolean addEntityUuid(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper + if (!this.knownUuids.add(entity.getUUID())) { + PersistentEntitySectionManager.LOGGER.warn("UUID of added entity already exists: {}", entity); + return false; +@@ -91,6 +92,7 @@ public class PersistentEntitySectionManager implements A + } + + private boolean addEntity(T entity, boolean existing) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper + // Paper start - chunk system hooks + // I don't want to know why this is a generic type. + Entity entityCasted = (Entity)entity; +@@ -144,19 +146,23 @@ public class PersistentEntitySectionManager implements A + } + + void startTicking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity start ticking"); // Paper + this.callbacks.onTickingStart(entity); + } + + void stopTicking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity stop ticking"); // Paper + this.callbacks.onTickingEnd(entity); + } + + void startTracking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity start tracking"); // Paper + this.visibleEntityStorage.add(entity); + this.callbacks.onTrackingStart(entity); + } + + void stopTracking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity stop tracking"); // Paper + this.callbacks.onTrackingEnd(entity); + this.visibleEntityStorage.remove(entity); + } +@@ -168,6 +174,7 @@ public class PersistentEntitySectionManager implements A + } + + public void updateChunkStatus(ChunkPos chunkPos, Visibility trackingStatus) { ++ org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper + long i = chunkPos.toLong(); + + if (trackingStatus == Visibility.HIDDEN) { +@@ -212,6 +219,7 @@ public class PersistentEntitySectionManager implements A + } + + public void ensureChunkQueuedForLoad(long chunkPos) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper + PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(chunkPos); + + if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) { +@@ -256,6 +264,7 @@ public class PersistentEntitySectionManager implements A + } + + private void requestChunkLoad(long chunkPos) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk load request"); // Paper + this.chunkLoadStatuses.put(chunkPos, PersistentEntitySectionManager.ChunkLoadStatus.PENDING); + ChunkPos chunkcoordintpair = new ChunkPos(chunkPos); + CompletableFuture completablefuture = this.permanentStorage.loadEntities(chunkcoordintpair); +@@ -269,6 +278,7 @@ public class PersistentEntitySectionManager implements A + } + + private boolean processChunkUnload(long chunkPos) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk unload process"); // Paper + boolean flag = this.storeChunkSections(chunkPos, (entityaccess) -> { + entityaccess.getPassengersAndSelf().forEach(this::unloadEntity); + }, true); // CraftBukkit - add boolean for event call +@@ -293,6 +303,7 @@ public class PersistentEntitySectionManager implements A + } + + private void processPendingLoads() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper + ChunkEntities chunkentities; // CraftBukkit - decompile error + + while ((chunkentities = (ChunkEntities) this.loadingInbox.poll()) != null) { +@@ -309,6 +320,7 @@ public class PersistentEntitySectionManager implements A + } + + public void tick() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper + this.processPendingLoads(); + this.processUnloads(); + } +@@ -329,6 +341,7 @@ public class PersistentEntitySectionManager implements A + } + + public void autoSave() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity manager autosave"); // Paper + this.getAllChunksToSave().forEach((java.util.function.LongConsumer) (i) -> { // CraftBukkit - decompile error + boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN; + +@@ -343,6 +356,7 @@ public class PersistentEntitySectionManager implements A + } + + public void saveAll() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper + LongSet longset = this.getAllChunksToSave(); + + while (!longset.isEmpty()) { +@@ -450,6 +464,7 @@ public class PersistentEntitySectionManager implements A + long i = SectionPos.asLong(blockposition); + + if (i != this.currentSectionKey) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper + Visibility visibility = this.currentSection.getStatus(); + + if (!this.currentSection.remove(this.entity)) { +@@ -504,6 +519,7 @@ public class PersistentEntitySectionManager implements A + + @Override + public void onRemove(Entity.RemovalReason reason) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity remove"); // Paper + if (!this.currentSection.remove(this.entity)) { + PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), reason}); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index d650822155f4628ea9d61ecbd4208520746aa59f..0ab6a9496e76aca6815bb8deebb8facd80a6b912 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1755,6 +1755,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void playSound(Location loc, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { ++ org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper + if (loc == null || sound == null || category == null) return; + + double x = loc.getX(); +@@ -1766,6 +1767,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void playSound(Location loc, String sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { ++ org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper + if (loc == null || sound == null || category == null) return; + + double x = loc.getX(); +@@ -1798,6 +1800,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void playSound(Entity entity, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { ++ org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper + if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; + + ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(CraftSound.bukkitToMinecraftHolder(sound), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); +@@ -1818,6 +1821,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void playSound(Entity entity, String sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { ++ org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper + if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; + + ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(Holder.direct(SoundEvent.createVariableRangeEvent(ResourceLocation.parse(sound))), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 5d6e4f2aeca9be4dd4504bc93b006e89ef875931..10a95c1a40597867ffd2974037bfed86dd6deda4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -534,6 +534,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + + @Override + public boolean addPotionEffect(PotionEffect effect, boolean force) { ++ org.spigotmc.AsyncCatcher.catchOp("effect add"); // Paper + this.getHandle().addEffect(org.bukkit.craftbukkit.potion.CraftPotionUtil.fromBukkit(effect), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon + return true; + } +diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java +index bbf0d9d9c44fe8d7add2f978994ec129420814c7..ef2598760458833021ef1bee92137f42c9fe591f 100644 +--- a/src/main/java/org/spigotmc/AsyncCatcher.java ++++ b/src/main/java/org/spigotmc/AsyncCatcher.java +@@ -11,6 +11,7 @@ public class AsyncCatcher + { + if ( AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread ) + { ++ MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); // Paper + throw new IllegalStateException( "Asynchronous " + reason + "!" ); + } + } diff --git a/patches/server/0590-Add-paper-mobcaps-and-paper-playermobcaps.patch b/patches/server/0590-Add-paper-mobcaps-and-paper-playermobcaps.patch new file mode 100644 index 0000000000..d04dadb215 --- /dev/null +++ b/patches/server/0590-Add-paper-mobcaps-and-paper-playermobcaps.patch @@ -0,0 +1,343 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Mon, 16 Aug 2021 01:31:54 -0500 +Subject: [PATCH] Add '/paper mobcaps' and '/paper playermobcaps' + +Add commands to get the mobcaps for a world, as well as the mobcaps for +each player when per-player mob spawning is enabled. + +Also has a hover text on each mob category listing what entity types are +in said category + +diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java +index cdad0fd5257ae842f83b9c1c98b4565b468d4f54..fd4f37711989431f997d77fb0917f8a9232ce53f 100644 +--- a/src/main/java/io/papermc/paper/command/PaperCommand.java ++++ b/src/main/java/io/papermc/paper/command/PaperCommand.java +@@ -40,6 +40,7 @@ public final class PaperCommand extends Command { + commands.put(Set.of("dumpplugins"), new DumpPluginsCommand()); + commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); + commands.put(Set.of("dumpitem"), new DumpItemCommand()); ++ commands.put(Set.of("mobcaps", "playermobcaps"), new MobcapsCommand()); + + 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/MobcapsCommand.java b/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d3b39d88a72ca25057fd8574d32f28db0d420818 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java +@@ -0,0 +1,229 @@ ++package io.papermc.paper.command.subcommands; ++ ++import com.google.common.collect.ImmutableMap; ++import io.papermc.paper.command.CommandUtil; ++import io.papermc.paper.command.PaperSubcommand; ++import java.util.ArrayList; ++import java.util.Collections; ++import java.util.List; ++import java.util.Map; ++import java.util.function.ToIntFunction; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.ComponentLike; ++import net.kyori.adventure.text.JoinConfiguration; ++import net.kyori.adventure.text.TextComponent; ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.format.TextColor; ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.world.entity.MobCategory; ++import net.minecraft.world.level.NaturalSpawner; ++import org.bukkit.Bukkit; ++import org.bukkit.World; ++import org.bukkit.command.CommandSender; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.entity.CraftPlayer; ++import org.bukkit.entity.Player; ++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 MobcapsCommand implements PaperSubcommand { ++ static final Map MOB_CATEGORY_COLORS = ImmutableMap.builder() ++ .put(MobCategory.MONSTER, NamedTextColor.RED) ++ .put(MobCategory.CREATURE, NamedTextColor.GREEN) ++ .put(MobCategory.AMBIENT, NamedTextColor.GRAY) ++ .put(MobCategory.AXOLOTLS, TextColor.color(0x7324FF)) ++ .put(MobCategory.UNDERGROUND_WATER_CREATURE, TextColor.color(0x3541E6)) ++ .put(MobCategory.WATER_CREATURE, TextColor.color(0x006EFF)) ++ .put(MobCategory.WATER_AMBIENT, TextColor.color(0x00B3FF)) ++ .put(MobCategory.MISC, TextColor.color(0x636363)) ++ .build(); ++ ++ @Override ++ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { ++ switch (subCommand) { ++ case "mobcaps" -> this.printMobcaps(sender, args); ++ case "playermobcaps" -> this.printPlayerMobcaps(sender, args); ++ } ++ return true; ++ } ++ ++ @Override ++ public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { ++ return switch (subCommand) { ++ case "mobcaps" -> CommandUtil.getListMatchingLast(sender, args, this.suggestMobcaps(args)); ++ case "playermobcaps" -> CommandUtil.getListMatchingLast(sender, args, this.suggestPlayerMobcaps(sender, args)); ++ default -> throw new IllegalArgumentException(); ++ }; ++ } ++ ++ private List suggestMobcaps(final String[] args) { ++ if (args.length == 1) { ++ final List worlds = new ArrayList<>(Bukkit.getWorlds().stream().map(World::getName).toList()); ++ worlds.add("*"); ++ return worlds; ++ } ++ ++ return Collections.emptyList(); ++ } ++ ++ private List suggestPlayerMobcaps(final CommandSender sender, final String[] args) { ++ if (args.length == 1) { ++ final List list = new ArrayList<>(); ++ for (final Player player : Bukkit.getOnlinePlayers()) { ++ if (!(sender instanceof Player senderPlayer) || senderPlayer.canSee(player)) { ++ list.add(player.getName()); ++ } ++ } ++ return list; ++ } ++ ++ return Collections.emptyList(); ++ } ++ ++ private void printMobcaps(final CommandSender sender, final String[] args) { ++ final List worlds; ++ if (args.length == 0) { ++ if (sender instanceof Player player) { ++ worlds = List.of(player.getWorld()); ++ } else { ++ sender.sendMessage(Component.text("Must specify a world! ex: '/paper mobcaps world'", NamedTextColor.RED)); ++ return; ++ } ++ } else if (args.length == 1) { ++ final String input = args[0]; ++ if (input.equals("*")) { ++ worlds = Bukkit.getWorlds(); ++ } else { ++ final @Nullable World world = Bukkit.getWorld(input); ++ if (world == null) { ++ sender.sendMessage(Component.text("'" + input + "' is not a valid world!", NamedTextColor.RED)); ++ return; ++ } else { ++ worlds = List.of(world); ++ } ++ } ++ } else { ++ sender.sendMessage(Component.text("Too many arguments!", NamedTextColor.RED)); ++ return; ++ } ++ ++ for (final World world : worlds) { ++ final ServerLevel level = ((CraftWorld) world).getHandle(); ++ final NaturalSpawner.@Nullable SpawnState state = level.getChunkSource().getLastSpawnState(); ++ ++ final int chunks; ++ if (state == null) { ++ chunks = 0; ++ } else { ++ chunks = state.getSpawnableChunkCount(); ++ } ++ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(), ++ Component.text("Mobcaps for world: "), ++ Component.text(world.getName(), NamedTextColor.AQUA), ++ Component.text(" (" + chunks + " spawnable chunks)") ++ )); ++ ++ sender.sendMessage(createMobcapsComponent( ++ category -> { ++ if (state == null) { ++ return 0; ++ } else { ++ return state.getMobCategoryCounts().getOrDefault(category, 0); ++ } ++ }, ++ category -> NaturalSpawner.globalLimitForCategory(level, category, chunks) ++ )); ++ } ++ } ++ ++ private void printPlayerMobcaps(final CommandSender sender, final String[] args) { ++ final @Nullable Player player; ++ if (args.length == 0) { ++ if (sender instanceof Player pl) { ++ player = pl; ++ } else { ++ sender.sendMessage(Component.text("Must specify a player! ex: '/paper playermobcount playerName'", NamedTextColor.RED)); ++ return; ++ } ++ } else if (args.length == 1) { ++ final String input = args[0]; ++ player = Bukkit.getPlayerExact(input); ++ if (player == null) { ++ sender.sendMessage(Component.text("Could not find player named '" + input + "'", NamedTextColor.RED)); ++ return; ++ } ++ } else { ++ sender.sendMessage(Component.text("Too many arguments!", NamedTextColor.RED)); ++ return; ++ } ++ ++ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); ++ final ServerLevel level = serverPlayer.serverLevel(); ++ ++ if (!level.paperConfig().entities.spawning.perPlayerMobSpawns) { ++ sender.sendMessage(Component.text("Use '/paper mobcaps' for worlds where per-player mob spawning is disabled.", NamedTextColor.RED)); ++ return; ++ } ++ ++ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(), Component.text("Mobcaps for player: "), Component.text(player.getName(), NamedTextColor.GREEN))); ++ sender.sendMessage(createMobcapsComponent( ++ category -> level.chunkSource.chunkMap.getMobCountNear(serverPlayer, category), ++ category -> level.getWorld().getSpawnLimitUnsafe(org.bukkit.craftbukkit.util.CraftSpawnCategory.toBukkit(category)) ++ )); ++ } ++ ++ private static Component createMobcapsComponent(final ToIntFunction countGetter, final ToIntFunction limitGetter) { ++ return MOB_CATEGORY_COLORS.entrySet().stream() ++ .map(entry -> { ++ final MobCategory category = entry.getKey(); ++ final TextColor color = entry.getValue(); ++ ++ final Component categoryHover = Component.join(JoinConfiguration.noSeparators(), ++ Component.text("Entity types in category ", TextColor.color(0xE0E0E0)), ++ Component.text(category.getName(), color), ++ Component.text(':', NamedTextColor.GRAY), ++ Component.newline(), ++ Component.newline(), ++ BuiltInRegistries.ENTITY_TYPE.entrySet().stream() ++ .filter(it -> it.getValue().getCategory() == category) ++ .map(it -> Component.translatable(it.getValue().getDescriptionId())) ++ .collect(Component.toComponent(Component.text(", ", NamedTextColor.GRAY))) ++ ); ++ ++ final Component categoryComponent = Component.text() ++ .content(" " + category.getName()) ++ .color(color) ++ .hoverEvent(categoryHover) ++ .build(); ++ ++ final TextComponent.Builder builder = Component.text() ++ .append( ++ categoryComponent, ++ Component.text(": ", NamedTextColor.GRAY) ++ ); ++ final int limit = limitGetter.applyAsInt(category); ++ if (limit != -1) { ++ builder.append( ++ Component.text(countGetter.applyAsInt(category)), ++ Component.text("/", NamedTextColor.GRAY), ++ Component.text(limit) ++ ); ++ } else { ++ builder.append(Component.text() ++ .append( ++ Component.text('n'), ++ Component.text("/", NamedTextColor.GRAY), ++ Component.text('a') ++ ) ++ .hoverEvent(Component.text("This category does not naturally spawn."))); ++ } ++ return builder; ++ }) ++ .map(ComponentLike::asComponent) ++ .collect(Component.toComponent(Component.newline())); ++ } ++} +diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +index 606a60fe273974b71ed2bd40be819d848627e777..bf943feca387b77a3154773a59da7190d38d8621 100644 +--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java ++++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +@@ -172,6 +172,16 @@ public final class NaturalSpawner { + gameprofilerfiller.pop(); + } + ++ // Paper start - Add mobcaps commands ++ public static int globalLimitForCategory(final ServerLevel level, final MobCategory category, final int spawnableChunkCount) { ++ final int categoryLimit = level.getWorld().getSpawnLimitUnsafe(CraftSpawnCategory.toBukkit(category)); ++ if (categoryLimit < 1) { ++ return categoryLimit; ++ } ++ return categoryLimit * spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER; ++ } ++ // Paper end - Add mobcaps commands ++ + public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) { + 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 45d887f4143444321f563cdd7d084b2b9ccf911e..33d9f3778996eedc83064332a2fbbdc7c6a8ba90 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2334,6 +2334,11 @@ public final class CraftServer implements Server { + + @Override + public int getSpawnLimit(SpawnCategory spawnCategory) { ++ // Paper start - Add mobcaps commands ++ return this.getSpawnLimitUnsafe(spawnCategory); ++ } ++ public int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) { ++ // Paper end - Add mobcaps commands + return this.spawnCategoryLimit.getOrDefault(spawnCategory, -1); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 0ab6a9496e76aca6815bb8deebb8facd80a6b912..744e3631cd2d5c157c9b6023ca813e57c6f860d6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1713,9 +1713,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { + Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); + Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); + ++ // Paper start - Add mobcaps commands ++ return this.getSpawnLimitUnsafe(spawnCategory); ++ } ++ public final int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) { + int limit = this.spawnCategoryLimit.getOrDefault(spawnCategory, -1); + if (limit < 0) { +- limit = this.server.getSpawnLimit(spawnCategory); ++ limit = this.server.getSpawnLimitUnsafe(spawnCategory); ++ // Paper end - Add mobcaps commands + } + return limit; + } +diff --git a/src/test/java/io/papermc/paper/command/subcommands/MobcapsCommandTest.java b/src/test/java/io/papermc/paper/command/subcommands/MobcapsCommandTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6fdc77caa74845786c78a6ba087062b4d698cb82 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/command/subcommands/MobcapsCommandTest.java +@@ -0,0 +1,22 @@ ++package io.papermc.paper.command.subcommands; ++ ++import java.util.HashSet; ++import java.util.Set; ++import net.minecraft.world.entity.MobCategory; ++import org.bukkit.support.environment.Normal; ++import org.junit.jupiter.api.Assertions; ++import org.junit.jupiter.api.Test; ++ ++@Normal ++public class MobcapsCommandTest { ++ @Test ++ public void testMobCategoryColors() { ++ final Set missing = new HashSet<>(); ++ for (final MobCategory value : MobCategory.values()) { ++ if (!MobcapsCommand.MOB_CATEGORY_COLORS.containsKey(value)) { ++ missing.add(value.getName()); ++ } ++ } ++ Assertions.assertTrue(missing.isEmpty(), "MobcapsCommand.MOB_CATEGORY_COLORS map missing TextColors for [" + String.join(", ", missing + "]")); ++ } ++} diff --git a/patches/server/0590-Improve-and-expand-AsyncCatcher.patch b/patches/server/0590-Improve-and-expand-AsyncCatcher.patch deleted file mode 100644 index 3214e81ee8..0000000000 --- a/patches/server/0590-Improve-and-expand-AsyncCatcher.patch +++ /dev/null @@ -1,227 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Wed, 25 Aug 2021 20:17:12 -0700 -Subject: [PATCH] Improve and expand AsyncCatcher - -Log when the async catcher is tripped - The chunk system can swallow the exception given it's all - built with completablefuture, so ensure it is at least printed. - -Add/move several async catchers - -Async catch modifications to critical entity state - These used to be here from Spigot, but were dropped with 1.17. - Now in 1.17, this state is _even more_ critical than it was before, - so these must exist to catch stupid plugins. - -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 b9eb462cf7603fb4afe365f6f094c784a5ee1137..740363cfeb7808994c7e3824163af7af7862fb15 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1651,6 +1651,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - - public void internalTeleport(PositionMoveRotation positionmoverotation, Set set) { -+ org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper - // Paper start - Prevent teleporting dead entities - 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 7ee81d5891d9d18566012cd72a516870f529628e..a5d3e5b402ca0a2e806a783304d43eac9dc142ad 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1143,7 +1143,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) { -- org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot -+ // org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot // Paper - move to API - if (this.isTickingEffects) { - this.effectsToProcess.add(new ProcessableEffect(mobeffect, cause)); - return true; -diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -index 4eb0b0969325f39a7ae65492cccd482515a50142..5aa74c00a61282830d82359eae2b114e2a48b6d9 100644 ---- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -@@ -78,6 +78,7 @@ public class PersistentEntitySectionManager implements A - } - - private boolean addEntityUuid(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper - if (!this.knownUuids.add(entity.getUUID())) { - PersistentEntitySectionManager.LOGGER.warn("UUID of added entity already exists: {}", entity); - return false; -@@ -91,6 +92,7 @@ public class PersistentEntitySectionManager implements A - } - - private boolean addEntity(T entity, boolean existing) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper - // Paper start - chunk system hooks - // I don't want to know why this is a generic type. - Entity entityCasted = (Entity)entity; -@@ -144,19 +146,23 @@ public class PersistentEntitySectionManager implements A - } - - void startTicking(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity start ticking"); // Paper - this.callbacks.onTickingStart(entity); - } - - void stopTicking(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity stop ticking"); // Paper - this.callbacks.onTickingEnd(entity); - } - - void startTracking(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity start tracking"); // Paper - this.visibleEntityStorage.add(entity); - this.callbacks.onTrackingStart(entity); - } - - void stopTracking(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity stop tracking"); // Paper - this.callbacks.onTrackingEnd(entity); - this.visibleEntityStorage.remove(entity); - } -@@ -168,6 +174,7 @@ public class PersistentEntitySectionManager implements A - } - - public void updateChunkStatus(ChunkPos chunkPos, Visibility trackingStatus) { -+ org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper - long i = chunkPos.toLong(); - - if (trackingStatus == Visibility.HIDDEN) { -@@ -212,6 +219,7 @@ public class PersistentEntitySectionManager implements A - } - - public void ensureChunkQueuedForLoad(long chunkPos) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper - PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(chunkPos); - - if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) { -@@ -256,6 +264,7 @@ public class PersistentEntitySectionManager implements A - } - - private void requestChunkLoad(long chunkPos) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk load request"); // Paper - this.chunkLoadStatuses.put(chunkPos, PersistentEntitySectionManager.ChunkLoadStatus.PENDING); - ChunkPos chunkcoordintpair = new ChunkPos(chunkPos); - CompletableFuture completablefuture = this.permanentStorage.loadEntities(chunkcoordintpair); -@@ -269,6 +278,7 @@ public class PersistentEntitySectionManager implements A - } - - private boolean processChunkUnload(long chunkPos) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk unload process"); // Paper - boolean flag = this.storeChunkSections(chunkPos, (entityaccess) -> { - entityaccess.getPassengersAndSelf().forEach(this::unloadEntity); - }, true); // CraftBukkit - add boolean for event call -@@ -293,6 +303,7 @@ public class PersistentEntitySectionManager implements A - } - - private void processPendingLoads() { -+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper - ChunkEntities chunkentities; // CraftBukkit - decompile error - - while ((chunkentities = (ChunkEntities) this.loadingInbox.poll()) != null) { -@@ -309,6 +320,7 @@ public class PersistentEntitySectionManager implements A - } - - public void tick() { -+ org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper - this.processPendingLoads(); - this.processUnloads(); - } -@@ -329,6 +341,7 @@ public class PersistentEntitySectionManager implements A - } - - public void autoSave() { -+ org.spigotmc.AsyncCatcher.catchOp("Entity manager autosave"); // Paper - this.getAllChunksToSave().forEach((java.util.function.LongConsumer) (i) -> { // CraftBukkit - decompile error - boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN; - -@@ -343,6 +356,7 @@ public class PersistentEntitySectionManager implements A - } - - public void saveAll() { -+ org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper - LongSet longset = this.getAllChunksToSave(); - - while (!longset.isEmpty()) { -@@ -450,6 +464,7 @@ public class PersistentEntitySectionManager implements A - long i = SectionPos.asLong(blockposition); - - if (i != this.currentSectionKey) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper - Visibility visibility = this.currentSection.getStatus(); - - if (!this.currentSection.remove(this.entity)) { -@@ -504,6 +519,7 @@ public class PersistentEntitySectionManager implements A - - @Override - public void onRemove(Entity.RemovalReason reason) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity remove"); // Paper - if (!this.currentSection.remove(this.entity)) { - PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), reason}); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index d650822155f4628ea9d61ecbd4208520746aa59f..0ab6a9496e76aca6815bb8deebb8facd80a6b912 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1755,6 +1755,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void playSound(Location loc, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { -+ org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper - if (loc == null || sound == null || category == null) return; - - double x = loc.getX(); -@@ -1766,6 +1767,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void playSound(Location loc, String sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { -+ org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper - if (loc == null || sound == null || category == null) return; - - double x = loc.getX(); -@@ -1798,6 +1800,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void playSound(Entity entity, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { -+ org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper - if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; - - ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(CraftSound.bukkitToMinecraftHolder(sound), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); -@@ -1818,6 +1821,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void playSound(Entity entity, String sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { -+ org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper - if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; - - ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(Holder.direct(SoundEvent.createVariableRangeEvent(ResourceLocation.parse(sound))), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 5d6e4f2aeca9be4dd4504bc93b006e89ef875931..10a95c1a40597867ffd2974037bfed86dd6deda4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -534,6 +534,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - - @Override - public boolean addPotionEffect(PotionEffect effect, boolean force) { -+ org.spigotmc.AsyncCatcher.catchOp("effect add"); // Paper - this.getHandle().addEffect(org.bukkit.craftbukkit.potion.CraftPotionUtil.fromBukkit(effect), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon - return true; - } -diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java -index bbf0d9d9c44fe8d7add2f978994ec129420814c7..ef2598760458833021ef1bee92137f42c9fe591f 100644 ---- a/src/main/java/org/spigotmc/AsyncCatcher.java -+++ b/src/main/java/org/spigotmc/AsyncCatcher.java -@@ -11,6 +11,7 @@ public class AsyncCatcher - { - if ( AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread ) - { -+ MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); // Paper - throw new IllegalStateException( "Asynchronous " + reason + "!" ); - } - } diff --git a/patches/server/0591-Add-paper-mobcaps-and-paper-playermobcaps.patch b/patches/server/0591-Add-paper-mobcaps-and-paper-playermobcaps.patch deleted file mode 100644 index d04dadb215..0000000000 --- a/patches/server/0591-Add-paper-mobcaps-and-paper-playermobcaps.patch +++ /dev/null @@ -1,343 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Mon, 16 Aug 2021 01:31:54 -0500 -Subject: [PATCH] Add '/paper mobcaps' and '/paper playermobcaps' - -Add commands to get the mobcaps for a world, as well as the mobcaps for -each player when per-player mob spawning is enabled. - -Also has a hover text on each mob category listing what entity types are -in said category - -diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java -index cdad0fd5257ae842f83b9c1c98b4565b468d4f54..fd4f37711989431f997d77fb0917f8a9232ce53f 100644 ---- a/src/main/java/io/papermc/paper/command/PaperCommand.java -+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java -@@ -40,6 +40,7 @@ public final class PaperCommand extends Command { - commands.put(Set.of("dumpplugins"), new DumpPluginsCommand()); - commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); - commands.put(Set.of("dumpitem"), new DumpItemCommand()); -+ commands.put(Set.of("mobcaps", "playermobcaps"), new MobcapsCommand()); - - 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/MobcapsCommand.java b/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d3b39d88a72ca25057fd8574d32f28db0d420818 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java -@@ -0,0 +1,229 @@ -+package io.papermc.paper.command.subcommands; -+ -+import com.google.common.collect.ImmutableMap; -+import io.papermc.paper.command.CommandUtil; -+import io.papermc.paper.command.PaperSubcommand; -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.List; -+import java.util.Map; -+import java.util.function.ToIntFunction; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.ComponentLike; -+import net.kyori.adventure.text.JoinConfiguration; -+import net.kyori.adventure.text.TextComponent; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.format.TextColor; -+import net.minecraft.core.registries.BuiltInRegistries; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.entity.MobCategory; -+import net.minecraft.world.level.NaturalSpawner; -+import org.bukkit.Bukkit; -+import org.bukkit.World; -+import org.bukkit.command.CommandSender; -+import org.bukkit.craftbukkit.CraftWorld; -+import org.bukkit.craftbukkit.entity.CraftPlayer; -+import org.bukkit.entity.Player; -+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 MobcapsCommand implements PaperSubcommand { -+ static final Map MOB_CATEGORY_COLORS = ImmutableMap.builder() -+ .put(MobCategory.MONSTER, NamedTextColor.RED) -+ .put(MobCategory.CREATURE, NamedTextColor.GREEN) -+ .put(MobCategory.AMBIENT, NamedTextColor.GRAY) -+ .put(MobCategory.AXOLOTLS, TextColor.color(0x7324FF)) -+ .put(MobCategory.UNDERGROUND_WATER_CREATURE, TextColor.color(0x3541E6)) -+ .put(MobCategory.WATER_CREATURE, TextColor.color(0x006EFF)) -+ .put(MobCategory.WATER_AMBIENT, TextColor.color(0x00B3FF)) -+ .put(MobCategory.MISC, TextColor.color(0x636363)) -+ .build(); -+ -+ @Override -+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ switch (subCommand) { -+ case "mobcaps" -> this.printMobcaps(sender, args); -+ case "playermobcaps" -> this.printPlayerMobcaps(sender, args); -+ } -+ return true; -+ } -+ -+ @Override -+ public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { -+ return switch (subCommand) { -+ case "mobcaps" -> CommandUtil.getListMatchingLast(sender, args, this.suggestMobcaps(args)); -+ case "playermobcaps" -> CommandUtil.getListMatchingLast(sender, args, this.suggestPlayerMobcaps(sender, args)); -+ default -> throw new IllegalArgumentException(); -+ }; -+ } -+ -+ private List suggestMobcaps(final String[] args) { -+ if (args.length == 1) { -+ final List worlds = new ArrayList<>(Bukkit.getWorlds().stream().map(World::getName).toList()); -+ worlds.add("*"); -+ return worlds; -+ } -+ -+ return Collections.emptyList(); -+ } -+ -+ private List suggestPlayerMobcaps(final CommandSender sender, final String[] args) { -+ if (args.length == 1) { -+ final List list = new ArrayList<>(); -+ for (final Player player : Bukkit.getOnlinePlayers()) { -+ if (!(sender instanceof Player senderPlayer) || senderPlayer.canSee(player)) { -+ list.add(player.getName()); -+ } -+ } -+ return list; -+ } -+ -+ return Collections.emptyList(); -+ } -+ -+ private void printMobcaps(final CommandSender sender, final String[] args) { -+ final List worlds; -+ if (args.length == 0) { -+ if (sender instanceof Player player) { -+ worlds = List.of(player.getWorld()); -+ } else { -+ sender.sendMessage(Component.text("Must specify a world! ex: '/paper mobcaps world'", NamedTextColor.RED)); -+ return; -+ } -+ } else if (args.length == 1) { -+ final String input = args[0]; -+ if (input.equals("*")) { -+ worlds = Bukkit.getWorlds(); -+ } else { -+ final @Nullable World world = Bukkit.getWorld(input); -+ if (world == null) { -+ sender.sendMessage(Component.text("'" + input + "' is not a valid world!", NamedTextColor.RED)); -+ return; -+ } else { -+ worlds = List.of(world); -+ } -+ } -+ } else { -+ sender.sendMessage(Component.text("Too many arguments!", NamedTextColor.RED)); -+ return; -+ } -+ -+ for (final World world : worlds) { -+ final ServerLevel level = ((CraftWorld) world).getHandle(); -+ final NaturalSpawner.@Nullable SpawnState state = level.getChunkSource().getLastSpawnState(); -+ -+ final int chunks; -+ if (state == null) { -+ chunks = 0; -+ } else { -+ chunks = state.getSpawnableChunkCount(); -+ } -+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(), -+ Component.text("Mobcaps for world: "), -+ Component.text(world.getName(), NamedTextColor.AQUA), -+ Component.text(" (" + chunks + " spawnable chunks)") -+ )); -+ -+ sender.sendMessage(createMobcapsComponent( -+ category -> { -+ if (state == null) { -+ return 0; -+ } else { -+ return state.getMobCategoryCounts().getOrDefault(category, 0); -+ } -+ }, -+ category -> NaturalSpawner.globalLimitForCategory(level, category, chunks) -+ )); -+ } -+ } -+ -+ private void printPlayerMobcaps(final CommandSender sender, final String[] args) { -+ final @Nullable Player player; -+ if (args.length == 0) { -+ if (sender instanceof Player pl) { -+ player = pl; -+ } else { -+ sender.sendMessage(Component.text("Must specify a player! ex: '/paper playermobcount playerName'", NamedTextColor.RED)); -+ return; -+ } -+ } else if (args.length == 1) { -+ final String input = args[0]; -+ player = Bukkit.getPlayerExact(input); -+ if (player == null) { -+ sender.sendMessage(Component.text("Could not find player named '" + input + "'", NamedTextColor.RED)); -+ return; -+ } -+ } else { -+ sender.sendMessage(Component.text("Too many arguments!", NamedTextColor.RED)); -+ return; -+ } -+ -+ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); -+ final ServerLevel level = serverPlayer.serverLevel(); -+ -+ if (!level.paperConfig().entities.spawning.perPlayerMobSpawns) { -+ sender.sendMessage(Component.text("Use '/paper mobcaps' for worlds where per-player mob spawning is disabled.", NamedTextColor.RED)); -+ return; -+ } -+ -+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(), Component.text("Mobcaps for player: "), Component.text(player.getName(), NamedTextColor.GREEN))); -+ sender.sendMessage(createMobcapsComponent( -+ category -> level.chunkSource.chunkMap.getMobCountNear(serverPlayer, category), -+ category -> level.getWorld().getSpawnLimitUnsafe(org.bukkit.craftbukkit.util.CraftSpawnCategory.toBukkit(category)) -+ )); -+ } -+ -+ private static Component createMobcapsComponent(final ToIntFunction countGetter, final ToIntFunction limitGetter) { -+ return MOB_CATEGORY_COLORS.entrySet().stream() -+ .map(entry -> { -+ final MobCategory category = entry.getKey(); -+ final TextColor color = entry.getValue(); -+ -+ final Component categoryHover = Component.join(JoinConfiguration.noSeparators(), -+ Component.text("Entity types in category ", TextColor.color(0xE0E0E0)), -+ Component.text(category.getName(), color), -+ Component.text(':', NamedTextColor.GRAY), -+ Component.newline(), -+ Component.newline(), -+ BuiltInRegistries.ENTITY_TYPE.entrySet().stream() -+ .filter(it -> it.getValue().getCategory() == category) -+ .map(it -> Component.translatable(it.getValue().getDescriptionId())) -+ .collect(Component.toComponent(Component.text(", ", NamedTextColor.GRAY))) -+ ); -+ -+ final Component categoryComponent = Component.text() -+ .content(" " + category.getName()) -+ .color(color) -+ .hoverEvent(categoryHover) -+ .build(); -+ -+ final TextComponent.Builder builder = Component.text() -+ .append( -+ categoryComponent, -+ Component.text(": ", NamedTextColor.GRAY) -+ ); -+ final int limit = limitGetter.applyAsInt(category); -+ if (limit != -1) { -+ builder.append( -+ Component.text(countGetter.applyAsInt(category)), -+ Component.text("/", NamedTextColor.GRAY), -+ Component.text(limit) -+ ); -+ } else { -+ builder.append(Component.text() -+ .append( -+ Component.text('n'), -+ Component.text("/", NamedTextColor.GRAY), -+ Component.text('a') -+ ) -+ .hoverEvent(Component.text("This category does not naturally spawn."))); -+ } -+ return builder; -+ }) -+ .map(ComponentLike::asComponent) -+ .collect(Component.toComponent(Component.newline())); -+ } -+} -diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 606a60fe273974b71ed2bd40be819d848627e777..bf943feca387b77a3154773a59da7190d38d8621 100644 ---- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java -+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -172,6 +172,16 @@ public final class NaturalSpawner { - gameprofilerfiller.pop(); - } - -+ // Paper start - Add mobcaps commands -+ public static int globalLimitForCategory(final ServerLevel level, final MobCategory category, final int spawnableChunkCount) { -+ final int categoryLimit = level.getWorld().getSpawnLimitUnsafe(CraftSpawnCategory.toBukkit(category)); -+ if (categoryLimit < 1) { -+ return categoryLimit; -+ } -+ return categoryLimit * spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER; -+ } -+ // Paper end - Add mobcaps commands -+ - public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) { - 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 45d887f4143444321f563cdd7d084b2b9ccf911e..33d9f3778996eedc83064332a2fbbdc7c6a8ba90 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2334,6 +2334,11 @@ public final class CraftServer implements Server { - - @Override - public int getSpawnLimit(SpawnCategory spawnCategory) { -+ // Paper start - Add mobcaps commands -+ return this.getSpawnLimitUnsafe(spawnCategory); -+ } -+ public int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) { -+ // Paper end - Add mobcaps commands - return this.spawnCategoryLimit.getOrDefault(spawnCategory, -1); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 0ab6a9496e76aca6815bb8deebb8facd80a6b912..744e3631cd2d5c157c9b6023ca813e57c6f860d6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1713,9 +1713,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { - Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); - Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); - -+ // Paper start - Add mobcaps commands -+ return this.getSpawnLimitUnsafe(spawnCategory); -+ } -+ public final int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) { - int limit = this.spawnCategoryLimit.getOrDefault(spawnCategory, -1); - if (limit < 0) { -- limit = this.server.getSpawnLimit(spawnCategory); -+ limit = this.server.getSpawnLimitUnsafe(spawnCategory); -+ // Paper end - Add mobcaps commands - } - return limit; - } -diff --git a/src/test/java/io/papermc/paper/command/subcommands/MobcapsCommandTest.java b/src/test/java/io/papermc/paper/command/subcommands/MobcapsCommandTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6fdc77caa74845786c78a6ba087062b4d698cb82 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/command/subcommands/MobcapsCommandTest.java -@@ -0,0 +1,22 @@ -+package io.papermc.paper.command.subcommands; -+ -+import java.util.HashSet; -+import java.util.Set; -+import net.minecraft.world.entity.MobCategory; -+import org.bukkit.support.environment.Normal; -+import org.junit.jupiter.api.Assertions; -+import org.junit.jupiter.api.Test; -+ -+@Normal -+public class MobcapsCommandTest { -+ @Test -+ public void testMobCategoryColors() { -+ final Set missing = new HashSet<>(); -+ for (final MobCategory value : MobCategory.values()) { -+ if (!MobcapsCommand.MOB_CATEGORY_COLORS.containsKey(value)) { -+ missing.add(value.getName()); -+ } -+ } -+ Assertions.assertTrue(missing.isEmpty(), "MobcapsCommand.MOB_CATEGORY_COLORS map missing TextColors for [" + String.join(", ", missing + "]")); -+ } -+} diff --git a/patches/server/0591-Sanitize-ResourceLocation-error-logging.patch b/patches/server/0591-Sanitize-ResourceLocation-error-logging.patch new file mode 100644 index 0000000000..602f0d3b27 --- /dev/null +++ b/patches/server/0591-Sanitize-ResourceLocation-error-logging.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Thu, 26 Aug 2021 12:09:47 +0200 +Subject: [PATCH] Sanitize ResourceLocation error logging + + +diff --git a/src/main/java/net/minecraft/resources/ResourceLocation.java b/src/main/java/net/minecraft/resources/ResourceLocation.java +index 262660d115a5d5cbecfbae995955a24283e666b0..87afe84791af2d5e9f869cd4c09eed4bb5fee75b 100644 +--- a/src/main/java/net/minecraft/resources/ResourceLocation.java ++++ b/src/main/java/net/minecraft/resources/ResourceLocation.java +@@ -247,7 +247,7 @@ public final class ResourceLocation implements Comparable { + + private static String assertValidNamespace(String namespace, String path) { + if (!isValidNamespace(namespace)) { +- throw new ResourceLocationException("Non [a-z0-9_.-] character in namespace of location: " + namespace + ":" + path); ++ throw new ResourceLocationException("Non [a-z0-9_.-] character in namespace of location: " + org.apache.commons.lang3.StringUtils.normalizeSpace(namespace) + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(path)); // Paper - Sanitize ResourceLocation error logging + } else { + return namespace; + } +@@ -268,7 +268,7 @@ public final class ResourceLocation implements Comparable { + + private static String assertValidPath(String namespace, String path) { + if (!isValidPath(path)) { +- throw new ResourceLocationException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + path); ++ throw new ResourceLocationException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(path)); // Paper - Sanitize ResourceLocation error logging + } else { + return path; + } diff --git a/patches/server/0592-Manually-inline-methods-in-BlockPosition.patch b/patches/server/0592-Manually-inline-methods-in-BlockPosition.patch new file mode 100644 index 0000000000..67bbeaf54d --- /dev/null +++ b/patches/server/0592-Manually-inline-methods-in-BlockPosition.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 6 Jul 2020 22:48:48 -0700 +Subject: [PATCH] Manually inline methods in BlockPosition + + +diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java +index 57340f0f46d5429585d99712dd39347d30d9951b..bf3eb9259f97d6d5af01244f103dc6b19c185d50 100644 +--- a/src/main/java/net/minecraft/core/BlockPos.java ++++ b/src/main/java/net/minecraft/core/BlockPos.java +@@ -588,9 +588,9 @@ public class BlockPos extends Vec3i { + } + + public BlockPos.MutableBlockPos set(int x, int y, int z) { +- this.setX(x); +- this.setY(y); +- this.setZ(z); ++ this.x = x; // Paper - Perf: Manually inline methods in BlockPosition ++ this.y = y; // Paper - Perf: Manually inline methods in BlockPosition ++ this.z = z; // Paper - Perf: Manually inline methods in BlockPosition + return this; + } + +@@ -655,19 +655,19 @@ public class BlockPos extends Vec3i { + + @Override + public BlockPos.MutableBlockPos setX(int i) { +- super.setX(i); ++ this.x = i; // Paper - Perf: Manually inline methods in BlockPosition + return this; + } + + @Override + public BlockPos.MutableBlockPos setY(int i) { +- super.setY(i); ++ this.y = i; // Paper - Perf: Manually inline methods in BlockPosition + return this; + } + + @Override + public BlockPos.MutableBlockPos setZ(int i) { +- super.setZ(i); ++ this.z = i; // Paper - Perf: Manually inline methods in BlockPosition + return this; + } + +diff --git a/src/main/java/net/minecraft/core/Vec3i.java b/src/main/java/net/minecraft/core/Vec3i.java +index 7d5f99cac756c54e5922bf85d5d359edcc21f1e8..2f2bcc1b9b32e58bf70ae6c171177ceb333ed6cd 100644 +--- a/src/main/java/net/minecraft/core/Vec3i.java ++++ b/src/main/java/net/minecraft/core/Vec3i.java +@@ -16,9 +16,9 @@ public class Vec3i implements Comparable { + vec -> IntStream.of(vec.getX(), vec.getY(), vec.getZ()) + ); + public static final Vec3i ZERO = new Vec3i(0, 0, 0); +- private int x; +- private int y; +- private int z; ++ protected int x; // Paper - Perf: Manually inline methods in BlockPosition; protected ++ protected int y; // Paper - Perf: Manually inline methods in BlockPosition; protected ++ protected int z; // Paper - Perf: Manually inline methods in BlockPosition; protected + + public static Codec offsetCodec(int maxAbsValue) { + return CODEC.validate( diff --git a/patches/server/0592-Sanitize-ResourceLocation-error-logging.patch b/patches/server/0592-Sanitize-ResourceLocation-error-logging.patch deleted file mode 100644 index 602f0d3b27..0000000000 --- a/patches/server/0592-Sanitize-ResourceLocation-error-logging.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Thu, 26 Aug 2021 12:09:47 +0200 -Subject: [PATCH] Sanitize ResourceLocation error logging - - -diff --git a/src/main/java/net/minecraft/resources/ResourceLocation.java b/src/main/java/net/minecraft/resources/ResourceLocation.java -index 262660d115a5d5cbecfbae995955a24283e666b0..87afe84791af2d5e9f869cd4c09eed4bb5fee75b 100644 ---- a/src/main/java/net/minecraft/resources/ResourceLocation.java -+++ b/src/main/java/net/minecraft/resources/ResourceLocation.java -@@ -247,7 +247,7 @@ public final class ResourceLocation implements Comparable { - - private static String assertValidNamespace(String namespace, String path) { - if (!isValidNamespace(namespace)) { -- throw new ResourceLocationException("Non [a-z0-9_.-] character in namespace of location: " + namespace + ":" + path); -+ throw new ResourceLocationException("Non [a-z0-9_.-] character in namespace of location: " + org.apache.commons.lang3.StringUtils.normalizeSpace(namespace) + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(path)); // Paper - Sanitize ResourceLocation error logging - } else { - return namespace; - } -@@ -268,7 +268,7 @@ public final class ResourceLocation implements Comparable { - - private static String assertValidPath(String namespace, String path) { - if (!isValidPath(path)) { -- throw new ResourceLocationException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + path); -+ throw new ResourceLocationException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(path)); // Paper - Sanitize ResourceLocation error logging - } else { - return path; - } diff --git a/patches/server/0593-Manually-inline-methods-in-BlockPosition.patch b/patches/server/0593-Manually-inline-methods-in-BlockPosition.patch deleted file mode 100644 index 67bbeaf54d..0000000000 --- a/patches/server/0593-Manually-inline-methods-in-BlockPosition.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 6 Jul 2020 22:48:48 -0700 -Subject: [PATCH] Manually inline methods in BlockPosition - - -diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java -index 57340f0f46d5429585d99712dd39347d30d9951b..bf3eb9259f97d6d5af01244f103dc6b19c185d50 100644 ---- a/src/main/java/net/minecraft/core/BlockPos.java -+++ b/src/main/java/net/minecraft/core/BlockPos.java -@@ -588,9 +588,9 @@ public class BlockPos extends Vec3i { - } - - public BlockPos.MutableBlockPos set(int x, int y, int z) { -- this.setX(x); -- this.setY(y); -- this.setZ(z); -+ this.x = x; // Paper - Perf: Manually inline methods in BlockPosition -+ this.y = y; // Paper - Perf: Manually inline methods in BlockPosition -+ this.z = z; // Paper - Perf: Manually inline methods in BlockPosition - return this; - } - -@@ -655,19 +655,19 @@ public class BlockPos extends Vec3i { - - @Override - public BlockPos.MutableBlockPos setX(int i) { -- super.setX(i); -+ this.x = i; // Paper - Perf: Manually inline methods in BlockPosition - return this; - } - - @Override - public BlockPos.MutableBlockPos setY(int i) { -- super.setY(i); -+ this.y = i; // Paper - Perf: Manually inline methods in BlockPosition - return this; - } - - @Override - public BlockPos.MutableBlockPos setZ(int i) { -- super.setZ(i); -+ this.z = i; // Paper - Perf: Manually inline methods in BlockPosition - return this; - } - -diff --git a/src/main/java/net/minecraft/core/Vec3i.java b/src/main/java/net/minecraft/core/Vec3i.java -index 7d5f99cac756c54e5922bf85d5d359edcc21f1e8..2f2bcc1b9b32e58bf70ae6c171177ceb333ed6cd 100644 ---- a/src/main/java/net/minecraft/core/Vec3i.java -+++ b/src/main/java/net/minecraft/core/Vec3i.java -@@ -16,9 +16,9 @@ public class Vec3i implements Comparable { - vec -> IntStream.of(vec.getX(), vec.getY(), vec.getZ()) - ); - public static final Vec3i ZERO = new Vec3i(0, 0, 0); -- private int x; -- private int y; -- private int z; -+ protected int x; // Paper - Perf: Manually inline methods in BlockPosition; protected -+ protected int y; // Paper - Perf: Manually inline methods in BlockPosition; protected -+ protected int z; // Paper - Perf: Manually inline methods in BlockPosition; protected - - public static Codec offsetCodec(int maxAbsValue) { - return CODEC.validate( diff --git a/patches/server/0593-Name-craft-scheduler-threads-according-to-the-plugin.patch b/patches/server/0593-Name-craft-scheduler-threads-according-to-the-plugin.patch new file mode 100644 index 0000000000..30f250f235 --- /dev/null +++ b/patches/server/0593-Name-craft-scheduler-threads-according-to-the-plugin.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 19 Jul 2020 15:17:01 -0700 +Subject: [PATCH] Name craft scheduler threads according to the plugin using + them + +Provides quick access to culprits running far more threads than +they should be + +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java +index 365b7e7c665bec357fb76d1479bf17da6f603590..e97f6b76ef2fe21c7c2eca8d4a707e5866d70de9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java +@@ -25,7 +25,10 @@ class CraftAsyncTask extends CraftTask { + @Override + public void run() { + final Thread thread = Thread.currentThread(); +- synchronized (this.workers) { ++ // Paper start - name threads according to running plugin ++ final String nameBefore = thread.getName(); ++ thread.setName(nameBefore + " - " + this.getOwner().getName()); ++ try { synchronized (this.workers) { // Paper end - name threads according to running plugin + if (this.getPeriod() == CraftTask.CANCEL) { + // Never continue running after cancelled. + // Checking this with the lock is important! +@@ -92,6 +95,7 @@ class CraftAsyncTask extends CraftTask { + } + } + } ++ } finally { thread.setName(nameBefore); } // Paper - name threads according to running plugin + } + + LinkedList getWorkers() { diff --git a/patches/server/0594-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch b/patches/server/0594-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch new file mode 100644 index 0000000000..73d62bea98 --- /dev/null +++ b/patches/server/0594-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 20 Sep 2020 16:10:49 -0700 +Subject: [PATCH] Make sure inlined getChunkAt has inlined logic for loaded + chunks + +Tux did some profiling some time ago and showed that the +previous getChunkAt method which had inlined logic for loaded +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 68cee32833a3d683852e67e3727d62b84fa60cc4..a1731f09e724794be90dbf47e1d463a10cdb3052 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -351,7 +351,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + + @Override + public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline +- return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump ++ // Paper start - Perf: make sure loaded chunks get the inlined variant of this function ++ net.minecraft.server.level.ServerChunkCache cps = ((ServerLevel)this).getChunkSource(); ++ LevelChunk ifLoaded = cps.getChunkAtIfLoadedImmediately(chunkX, chunkZ); ++ if (ifLoaded != null) { ++ return ifLoaded; ++ } ++ return (LevelChunk) cps.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump ++ // Paper end - Perf: make sure loaded chunks get the inlined variant of this function + } + + // Paper start - if loaded diff --git a/patches/server/0594-Name-craft-scheduler-threads-according-to-the-plugin.patch b/patches/server/0594-Name-craft-scheduler-threads-according-to-the-plugin.patch deleted file mode 100644 index 30f250f235..0000000000 --- a/patches/server/0594-Name-craft-scheduler-threads-according-to-the-plugin.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 19 Jul 2020 15:17:01 -0700 -Subject: [PATCH] Name craft scheduler threads according to the plugin using - them - -Provides quick access to culprits running far more threads than -they should be - -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java -index 365b7e7c665bec357fb76d1479bf17da6f603590..e97f6b76ef2fe21c7c2eca8d4a707e5866d70de9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java -@@ -25,7 +25,10 @@ class CraftAsyncTask extends CraftTask { - @Override - public void run() { - final Thread thread = Thread.currentThread(); -- synchronized (this.workers) { -+ // Paper start - name threads according to running plugin -+ final String nameBefore = thread.getName(); -+ thread.setName(nameBefore + " - " + this.getOwner().getName()); -+ try { synchronized (this.workers) { // Paper end - name threads according to running plugin - if (this.getPeriod() == CraftTask.CANCEL) { - // Never continue running after cancelled. - // Checking this with the lock is important! -@@ -92,6 +95,7 @@ class CraftAsyncTask extends CraftTask { - } - } - } -+ } finally { thread.setName(nameBefore); } // Paper - name threads according to running plugin - } - - LinkedList getWorkers() { diff --git a/patches/server/0595-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch b/patches/server/0595-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch new file mode 100644 index 0000000000..eff1d0a95f --- /dev/null +++ b/patches/server/0595-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 11 Apr 2021 02:58:48 -0700 +Subject: [PATCH] Don't read neighbour chunk data off disk when converting + chunks + +Lighting is purged on update anyways, so let's not add more +into the conversion process + +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java +index 909acbf5b8c6edcb4529647c11464d911d6f8c15..7d5e2e6e96ea9017334dddade54a9dcb37518642 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java +@@ -47,6 +47,7 @@ public class ChunkStorage implements AutoCloseable { + + // CraftBukkit start + private boolean check(ServerChunkCache cps, int x, int z) { ++ if (true) return true; // Paper - Perf: this isn't even needed anymore, light is purged updating to 1.14+, why are we holding up the conversion process reading chunk data off disk - return true, we need to set light populated to true so the converter recognizes the chunk as being "full" + ChunkPos pos = new ChunkPos(x, z); + if (cps != null) { + com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); diff --git a/patches/server/0595-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch b/patches/server/0595-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch deleted file mode 100644 index 73d62bea98..0000000000 --- a/patches/server/0595-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 20 Sep 2020 16:10:49 -0700 -Subject: [PATCH] Make sure inlined getChunkAt has inlined logic for loaded - chunks - -Tux did some profiling some time ago and showed that the -previous getChunkAt method which had inlined logic for loaded -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 68cee32833a3d683852e67e3727d62b84fa60cc4..a1731f09e724794be90dbf47e1d463a10cdb3052 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -351,7 +351,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - - @Override - public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline -- return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump -+ // Paper start - Perf: make sure loaded chunks get the inlined variant of this function -+ net.minecraft.server.level.ServerChunkCache cps = ((ServerLevel)this).getChunkSource(); -+ LevelChunk ifLoaded = cps.getChunkAtIfLoadedImmediately(chunkX, chunkZ); -+ if (ifLoaded != null) { -+ return ifLoaded; -+ } -+ return (LevelChunk) cps.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump -+ // Paper end - Perf: make sure loaded chunks get the inlined variant of this function - } - - // Paper start - if loaded diff --git a/patches/server/0596-Don-t-lookup-fluid-state-when-raytracing-skip-air-bl.patch b/patches/server/0596-Don-t-lookup-fluid-state-when-raytracing-skip-air-bl.patch new file mode 100644 index 0000000000..1626fb7b50 --- /dev/null +++ b/patches/server/0596-Don-t-lookup-fluid-state-when-raytracing-skip-air-bl.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Fri, 28 Aug 2020 12:33:47 -0700 +Subject: [PATCH] Don't lookup fluid state when raytracing, skip air blocks + +Just use the iblockdata already retrieved, removes a getType call. + +Also save approx. 5% for the raytrace call, as most (expensive) +raytracing tends to go through air and returning early is an +easy win. The remaining problems with this function +are mostly with the block getting itself. + +diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java +index 6bf3019ff06501e82de5976417fd98a10ae6334a..e69473307b30d2b805fc1723ae8f6f2be76310ef 100644 +--- a/src/main/java/net/minecraft/world/level/BlockGetter.java ++++ b/src/main/java/net/minecraft/world/level/BlockGetter.java +@@ -80,7 +80,8 @@ 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 +- FluidState fluid = this.getFluidState(blockposition); ++ if (iblockdata.isAir()) return null; // Paper - Perf: optimise air cases ++ FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: don't need to go to world state again + Vec3 vec3d = raytrace1.getFrom(); + Vec3 vec3d1 = raytrace1.getTo(); + VoxelShape voxelshape = raytrace1.getBlockShape(iblockdata, this, blockposition); diff --git a/patches/server/0596-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch b/patches/server/0596-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch deleted file mode 100644 index eff1d0a95f..0000000000 --- a/patches/server/0596-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 11 Apr 2021 02:58:48 -0700 -Subject: [PATCH] Don't read neighbour chunk data off disk when converting - chunks - -Lighting is purged on update anyways, so let's not add more -into the conversion process - -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -index 909acbf5b8c6edcb4529647c11464d911d6f8c15..7d5e2e6e96ea9017334dddade54a9dcb37518642 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -@@ -47,6 +47,7 @@ public class ChunkStorage implements AutoCloseable { - - // CraftBukkit start - private boolean check(ServerChunkCache cps, int x, int z) { -+ if (true) return true; // Paper - Perf: this isn't even needed anymore, light is purged updating to 1.14+, why are we holding up the conversion process reading chunk data off disk - return true, we need to set light populated to true so the converter recognizes the chunk as being "full" - ChunkPos pos = new ChunkPos(x, z); - if (cps != null) { - com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); diff --git a/patches/server/0597-Don-t-lookup-fluid-state-when-raytracing-skip-air-bl.patch b/patches/server/0597-Don-t-lookup-fluid-state-when-raytracing-skip-air-bl.patch deleted file mode 100644 index 1626fb7b50..0000000000 --- a/patches/server/0597-Don-t-lookup-fluid-state-when-raytracing-skip-air-bl.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Fri, 28 Aug 2020 12:33:47 -0700 -Subject: [PATCH] Don't lookup fluid state when raytracing, skip air blocks - -Just use the iblockdata already retrieved, removes a getType call. - -Also save approx. 5% for the raytrace call, as most (expensive) -raytracing tends to go through air and returning early is an -easy win. The remaining problems with this function -are mostly with the block getting itself. - -diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java -index 6bf3019ff06501e82de5976417fd98a10ae6334a..e69473307b30d2b805fc1723ae8f6f2be76310ef 100644 ---- a/src/main/java/net/minecraft/world/level/BlockGetter.java -+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java -@@ -80,7 +80,8 @@ 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 -- FluidState fluid = this.getFluidState(blockposition); -+ if (iblockdata.isAir()) return null; // Paper - Perf: optimise air cases -+ FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: don't need to go to world state again - Vec3 vec3d = raytrace1.getFrom(); - Vec3 vec3d1 = raytrace1.getTo(); - VoxelShape voxelshape = raytrace1.getBlockShape(iblockdata, this, blockposition); diff --git a/patches/server/0597-Oprimise-map-impl-for-tracked-players.patch b/patches/server/0597-Oprimise-map-impl-for-tracked-players.patch new file mode 100644 index 0000000000..cea8c3752e --- /dev/null +++ b/patches/server/0597-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 69f54e812794b23e5f54606da86f71163f5f0bbe..2d325c998e40a65af10d6adbb0dc304bea50e3d8 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1508,7 +1508,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/0598-Add-missing-InventoryType.patch b/patches/server/0598-Add-missing-InventoryType.patch new file mode 100644 index 0000000000..768c150fc1 --- /dev/null +++ b/patches/server/0598-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 bc5ec42a54401a2275c05f0f506ba89f00c19ec9..c6159c70f7a37b9bffe268b91905ce848d1d2927 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +@@ -529,6 +529,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/0598-Oprimise-map-impl-for-tracked-players.patch b/patches/server/0598-Oprimise-map-impl-for-tracked-players.patch deleted file mode 100644 index cea8c3752e..0000000000 --- a/patches/server/0598-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 69f54e812794b23e5f54606da86f71163f5f0bbe..2d325c998e40a65af10d6adbb0dc304bea50e3d8 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1508,7 +1508,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/0599-Add-missing-InventoryType.patch b/patches/server/0599-Add-missing-InventoryType.patch deleted file mode 100644 index 768c150fc1..0000000000 --- a/patches/server/0599-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 bc5ec42a54401a2275c05f0f506ba89f00c19ec9..c6159c70f7a37b9bffe268b91905ce848d1d2927 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -@@ -529,6 +529,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/0599-Optimise-BlockSoil-nearby-water-lookup.patch b/patches/server/0599-Optimise-BlockSoil-nearby-water-lookup.patch new file mode 100644 index 0000000000..4a5d6c5b9d --- /dev/null +++ b/patches/server/0599-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/0600-Fix-merchant-inventory-not-closing-on-entity-removal.patch b/patches/server/0600-Fix-merchant-inventory-not-closing-on-entity-removal.patch new file mode 100644 index 0000000000..553f865869 --- /dev/null +++ b/patches/server/0600-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 1301622961ffdcfcccc9658a0e4498bc04ad93f5..3ed78515fed78f5a679b9002e2e3a0aa6984aa70 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2313,6 +2313,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/0600-Optimise-BlockSoil-nearby-water-lookup.patch b/patches/server/0600-Optimise-BlockSoil-nearby-water-lookup.patch deleted file mode 100644 index 4a5d6c5b9d..0000000000 --- a/patches/server/0600-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/0601-Check-requirement-before-suggesting-root-nodes.patch b/patches/server/0601-Check-requirement-before-suggesting-root-nodes.patch new file mode 100644 index 0000000000..fce5e326f9 --- /dev/null +++ b/patches/server/0601-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/0601-Fix-merchant-inventory-not-closing-on-entity-removal.patch b/patches/server/0601-Fix-merchant-inventory-not-closing-on-entity-removal.patch deleted file mode 100644 index 553f865869..0000000000 --- a/patches/server/0601-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 1301622961ffdcfcccc9658a0e4498bc04ad93f5..3ed78515fed78f5a679b9002e2e3a0aa6984aa70 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2313,6 +2313,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/0602-Check-requirement-before-suggesting-root-nodes.patch b/patches/server/0602-Check-requirement-before-suggesting-root-nodes.patch deleted file mode 100644 index fce5e326f9..0000000000 --- a/patches/server/0602-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/0602-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch b/patches/server/0602-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch new file mode 100644 index 0000000000..064dbb8062 --- /dev/null +++ b/patches/server/0602-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 740363cfeb7808994c7e3824163af7af7862fb15..88ba98aee07764e418edb9052075acea557ceec9 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -758,6 +758,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/0603-Add-packet-limiter-config.patch b/patches/server/0603-Add-packet-limiter-config.patch new file mode 100644 index 0000000000..e49a44446e --- /dev/null +++ b/patches/server/0603-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 f5fe87103ce53ba07b43c6c10fc9dafcc5ea4958..72e69f60fb687f102c963b61042b19162a5ec0b2 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/0603-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch b/patches/server/0603-Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch deleted file mode 100644 index 064dbb8062..0000000000 --- a/patches/server/0603-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 740363cfeb7808994c7e3824163af7af7862fb15..88ba98aee07764e418edb9052075acea557ceec9 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -758,6 +758,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/0604-Add-packet-limiter-config.patch b/patches/server/0604-Add-packet-limiter-config.patch deleted file mode 100644 index e49a44446e..0000000000 --- a/patches/server/0604-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 f5fe87103ce53ba07b43c6c10fc9dafcc5ea4958..72e69f60fb687f102c963b61042b19162a5ec0b2 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/0604-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch b/patches/server/0604-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch new file mode 100644 index 0000000000..f5c3a81df3 --- /dev/null +++ b/patches/server/0604-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/0605-Ensure-valid-vehicle-status.patch b/patches/server/0605-Ensure-valid-vehicle-status.patch new file mode 100644 index 0000000000..472fc15d9d --- /dev/null +++ b/patches/server/0605-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 0401e274a600b87c4c983a90819a17c9dfbd7172..0efd5d23924efec5e2bff0c7b3dddb6e97723e29 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -696,7 +696,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/0605-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch b/patches/server/0605-Fix-setPatternColor-on-tropical-fish-bucket-meta.patch deleted file mode 100644 index f5c3a81df3..0000000000 --- a/patches/server/0605-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/0606-Ensure-valid-vehicle-status.patch b/patches/server/0606-Ensure-valid-vehicle-status.patch deleted file mode 100644 index 88fa596782..0000000000 --- a/patches/server/0606-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 215be207e29254312bb85f259a684a7de6876aa9..e2a8e0291a5c0c00d7d6135a0d34fb8bab7b4cd5 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -696,7 +696,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/0606-Prevent-softlocked-end-exit-portal-generation.patch b/patches/server/0606-Prevent-softlocked-end-exit-portal-generation.patch new file mode 100644 index 0000000000..4c54f27f94 --- /dev/null +++ b/patches/server/0606-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/0607-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch b/patches/server/0607-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch new file mode 100644 index 0000000000..a145d67c1a --- /dev/null +++ b/patches/server/0607-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 3acae3afbfc7c15442ddde7aaf250dac5be2bde5..a6c6d0fe89af4265d0034b8d03f4fdb8d5c1a04f 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/0607-Prevent-softlocked-end-exit-portal-generation.patch b/patches/server/0607-Prevent-softlocked-end-exit-portal-generation.patch deleted file mode 100644 index 4c54f27f94..0000000000 --- a/patches/server/0607-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/0608-Don-t-log-debug-logging-being-disabled.patch b/patches/server/0608-Don-t-log-debug-logging-being-disabled.patch new file mode 100644 index 0000000000..8e733b1cea --- /dev/null +++ b/patches/server/0608-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/0608-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch b/patches/server/0608-Fix-CocaoDecorator-causing-a-crash-when-trying-to-ge.patch deleted file mode 100644 index a145d67c1a..0000000000 --- a/patches/server/0608-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 3acae3afbfc7c15442ddde7aaf250dac5be2bde5..a6c6d0fe89af4265d0034b8d03f4fdb8d5c1a04f 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/0609-Don-t-log-debug-logging-being-disabled.patch b/patches/server/0609-Don-t-log-debug-logging-being-disabled.patch deleted file mode 100644 index 8e733b1cea..0000000000 --- a/patches/server/0609-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/0609-fix-various-menus-with-empty-level-accesses.patch b/patches/server/0609-fix-various-menus-with-empty-level-accesses.patch new file mode 100644 index 0000000000..efe5d1ddce --- /dev/null +++ b/patches/server/0609-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/0610-Preserve-overstacked-loot.patch b/patches/server/0610-Preserve-overstacked-loot.patch new file mode 100644 index 0000000000..db50d2fd8a --- /dev/null +++ b/patches/server/0610-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/0610-fix-various-menus-with-empty-level-accesses.patch b/patches/server/0610-fix-various-menus-with-empty-level-accesses.patch deleted file mode 100644 index efe5d1ddce..0000000000 --- a/patches/server/0610-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/0611-Preserve-overstacked-loot.patch b/patches/server/0611-Preserve-overstacked-loot.patch deleted file mode 100644 index db50d2fd8a..0000000000 --- a/patches/server/0611-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/0611-Update-head-rotation-in-missing-places.patch b/patches/server/0611-Update-head-rotation-in-missing-places.patch new file mode 100644 index 0000000000..33df7692a3 --- /dev/null +++ b/patches/server/0611-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 fe1a30e4c73dbecbd44187dbdef0d98b7613e524..c19c866cfd709a5d6f4c62d55f12e5938493466b 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -1938,6 +1938,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) { +@@ -1980,6 +1981,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/0612-Update-head-rotation-in-missing-places.patch b/patches/server/0612-Update-head-rotation-in-missing-places.patch deleted file mode 100644 index 0d645ccc95..0000000000 --- a/patches/server/0612-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 ca0353307f6a1d937ec9663a19489135b9844963..6457b529ce3dead642f4435c76c3e8a1e31023ba 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1938,6 +1938,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) { -@@ -1980,6 +1981,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/0612-prevent-unintended-light-block-manipulation.patch b/patches/server/0612-prevent-unintended-light-block-manipulation.patch new file mode 100644 index 0000000000..e9851e3744 --- /dev/null +++ b/patches/server/0612-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 2be8855b2cd50e599d80e1ff5dc13d66451dff9d..9f6bb23b6021a99d4bb09d57659943cfdb4b673f 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/0613-Fix-CraftCriteria-defaults-map.patch b/patches/server/0613-Fix-CraftCriteria-defaults-map.patch new file mode 100644 index 0000000000..3e79bd7fb7 --- /dev/null +++ b/patches/server/0613-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/0613-prevent-unintended-light-block-manipulation.patch b/patches/server/0613-prevent-unintended-light-block-manipulation.patch deleted file mode 100644 index e9851e3744..0000000000 --- a/patches/server/0613-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 2be8855b2cd50e599d80e1ff5dc13d66451dff9d..9f6bb23b6021a99d4bb09d57659943cfdb4b673f 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/0614-Fix-CraftCriteria-defaults-map.patch b/patches/server/0614-Fix-CraftCriteria-defaults-map.patch deleted file mode 100644 index 3e79bd7fb7..0000000000 --- a/patches/server/0614-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/0614-Fix-upstreams-block-state-factories.patch b/patches/server/0614-Fix-upstreams-block-state-factories.patch new file mode 100644 index 0000000000..d5198201c5 --- /dev/null +++ b/patches/server/0614-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 8e091ac441acf88a5c8597c6d2923efa5662092e..b1ed43287d522e08a967ba751a851776351916e7 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 +@@ -370,7 +370,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/0615-Configurable-feature-seeds.patch b/patches/server/0615-Configurable-feature-seeds.patch new file mode 100644 index 0000000000..9a0502f3a7 --- /dev/null +++ b/patches/server/0615-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 416b1afcbab093f45900a4d55708609ba5a7de7a..fde17b4e2607fc443a33aea3a631aae6ccb71e2c 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -437,7 +437,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/0615-Fix-upstreams-block-state-factories.patch b/patches/server/0615-Fix-upstreams-block-state-factories.patch deleted file mode 100644 index d5198201c5..0000000000 --- a/patches/server/0615-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 8e091ac441acf88a5c8597c6d2923efa5662092e..b1ed43287d522e08a967ba751a851776351916e7 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 -@@ -370,7 +370,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/0616-Add-root-admin-user-detection.patch b/patches/server/0616-Add-root-admin-user-detection.patch new file mode 100644 index 0000000000..df739cc33c --- /dev/null +++ b/patches/server/0616-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/0616-Configurable-feature-seeds.patch b/patches/server/0616-Configurable-feature-seeds.patch deleted file mode 100644 index 9a0502f3a7..0000000000 --- a/patches/server/0616-Configurable-feature-seeds.patch +++ /dev/null @@ -1,27 +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/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index 416b1afcbab093f45900a4d55708609ba5a7de7a..fde17b4e2607fc443a33aea3a631aae6ccb71e2c 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -437,7 +437,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/0617-Add-root-admin-user-detection.patch b/patches/server/0617-Add-root-admin-user-detection.patch deleted file mode 100644 index df739cc33c..0000000000 --- a/patches/server/0617-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 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/0617-don-t-attempt-to-teleport-dead-entities.patch b/patches/server/0617-don-t-attempt-to-teleport-dead-entities.patch new file mode 100644 index 0000000000..e6ea0360ce --- /dev/null +++ b/patches/server/0617-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 c19c866cfd709a5d6f4c62d55f12e5938493466b..b60807aea433ddf35def3a97d7d3808c62f1b5ac 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -718,7 +718,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/0618-Prevent-excessive-velocity-through-repeated-crits.patch b/patches/server/0618-Prevent-excessive-velocity-through-repeated-crits.patch new file mode 100644 index 0000000000..c290d77cb1 --- /dev/null +++ b/patches/server/0618-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 a5d3e5b402ca0a2e806a783304d43eac9dc142ad..d46886a658c5058ba2c622daff96f5daf15ef3f3 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -2875,17 +2875,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/0618-don-t-attempt-to-teleport-dead-entities.patch b/patches/server/0618-don-t-attempt-to-teleport-dead-entities.patch deleted file mode 100644 index 1457012403..0000000000 --- a/patches/server/0618-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 6457b529ce3dead642f4435c76c3e8a1e31023ba..7de1cd151d4ccea4b4f069cc50fc399038ce5de9 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -718,7 +718,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/0619-Prevent-excessive-velocity-through-repeated-crits.patch b/patches/server/0619-Prevent-excessive-velocity-through-repeated-crits.patch deleted file mode 100644 index c290d77cb1..0000000000 --- a/patches/server/0619-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 a5d3e5b402ca0a2e806a783304d43eac9dc142ad..d46886a658c5058ba2c622daff96f5daf15ef3f3 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2875,17 +2875,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/0619-Remove-client-side-code-using-deprecated-for-removal.patch b/patches/server/0619-Remove-client-side-code-using-deprecated-for-removal.patch new file mode 100644 index 0000000000..4a04ac055a --- /dev/null +++ b/patches/server/0619-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 e78f40f7f10a2ed0675b3cb9a2c5730dbc0141db..cc5e2710d3edeaf60284ed95c33999c701d0678a 100644 +--- a/src/main/java/net/minecraft/Util.java ++++ b/src/main/java/net/minecraft/Util.java +@@ -1087,16 +1087,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/0620-Fix-Spigot-growth-modifiers.patch b/patches/server/0620-Fix-Spigot-growth-modifiers.patch new file mode 100644 index 0000000000..4e7f192262 --- /dev/null +++ b/patches/server/0620-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 b4618129397fa5dbec3a6438fc20c57d91d1d1dd..81e572783157926383dd9baa58d30f5419c1616f 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 6fe896079c0ae622976c2055f8d13cda5ed3ea3d..1967ff3fcb94988be85985c4754904f0077de066 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/0620-Remove-client-side-code-using-deprecated-for-removal.patch b/patches/server/0620-Remove-client-side-code-using-deprecated-for-removal.patch deleted file mode 100644 index 4a04ac055a..0000000000 --- a/patches/server/0620-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 e78f40f7f10a2ed0675b3cb9a2c5730dbc0141db..cc5e2710d3edeaf60284ed95c33999c701d0678a 100644 ---- a/src/main/java/net/minecraft/Util.java -+++ b/src/main/java/net/minecraft/Util.java -@@ -1087,16 +1087,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/0621-Fix-Spigot-growth-modifiers.patch b/patches/server/0621-Fix-Spigot-growth-modifiers.patch deleted file mode 100644 index 4e7f192262..0000000000 --- a/patches/server/0621-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 b4618129397fa5dbec3a6438fc20c57d91d1d1dd..81e572783157926383dd9baa58d30f5419c1616f 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 6fe896079c0ae622976c2055f8d13cda5ed3ea3d..1967ff3fcb94988be85985c4754904f0077de066 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/0621-Prevent-ContainerOpenersCounter-openCount-from-going.patch b/patches/server/0621-Prevent-ContainerOpenersCounter-openCount-from-going.patch new file mode 100644 index 0000000000..b017de75d1 --- /dev/null +++ b/patches/server/0621-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/0622-Add-PlayerItemFrameChangeEvent.patch b/patches/server/0622-Add-PlayerItemFrameChangeEvent.patch new file mode 100644 index 0000000000..3124caa15b --- /dev/null +++ b/patches/server/0622-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 dc642c311b711ad97a598485ff38083ccda827af..916017571ecde95721df9bdc07c5e7b5dc60c957 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/0622-Prevent-ContainerOpenersCounter-openCount-from-going.patch b/patches/server/0622-Prevent-ContainerOpenersCounter-openCount-from-going.patch deleted file mode 100644 index b017de75d1..0000000000 --- a/patches/server/0622-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/0623-Add-PlayerItemFrameChangeEvent.patch b/patches/server/0623-Add-PlayerItemFrameChangeEvent.patch deleted file mode 100644 index b7e908ab6e..0000000000 --- a/patches/server/0623-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/0623-Optimize-HashMapPalette.patch b/patches/server/0623-Optimize-HashMapPalette.patch new file mode 100644 index 0000000000..a490eb0c20 --- /dev/null +++ b/patches/server/0623-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/0624-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch b/patches/server/0624-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch new file mode 100644 index 0000000000..cde811d346 --- /dev/null +++ b/patches/server/0624-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 be44b03527bd17344f5d835ba9d0b47e4b55d45f..08956b81b9a3e5caf3adce6699149491ff190d90 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/0624-Optimize-HashMapPalette.patch b/patches/server/0624-Optimize-HashMapPalette.patch deleted file mode 100644 index a490eb0c20..0000000000 --- a/patches/server/0624-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/0625-Add-more-Campfire-API.patch b/patches/server/0625-Add-more-Campfire-API.patch new file mode 100644 index 0000000000..c490c151c3 --- /dev/null +++ b/patches/server/0625-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/0625-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch b/patches/server/0625-Fix-ChunkSnapshot-isSectionEmpty-int-and-optimize-Pa.patch deleted file mode 100644 index cde811d346..0000000000 --- a/patches/server/0625-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 be44b03527bd17344f5d835ba9d0b47e4b55d45f..08956b81b9a3e5caf3adce6699149491ff190d90 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/0626-Add-more-Campfire-API.patch b/patches/server/0626-Add-more-Campfire-API.patch deleted file mode 100644 index c490c151c3..0000000000 --- a/patches/server/0626-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/0626-Forward-CraftEntity-in-teleport-command.patch b/patches/server/0626-Forward-CraftEntity-in-teleport-command.patch new file mode 100644 index 0000000000..126144476d --- /dev/null +++ b/patches/server/0626-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 b60807aea433ddf35def3a97d7d3808c62f1b5ac..46884e4d6b7c434d58bd2f7e7e27cfcdcd0e2065 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3511,6 +3511,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"); +@@ -3648,8 +3655,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/0627-Forward-CraftEntity-in-teleport-command.patch b/patches/server/0627-Forward-CraftEntity-in-teleport-command.patch deleted file mode 100644 index 5318066ae6..0000000000 --- a/patches/server/0627-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 7de1cd151d4ccea4b4f069cc50fc399038ce5de9..68b072415d312e22ef00da3689efcd4631934163 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3511,6 +3511,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"); -@@ -3648,8 +3655,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/0627-Improve-scoreboard-entries.patch b/patches/server/0627-Improve-scoreboard-entries.patch new file mode 100644 index 0000000000..8acac86ce3 --- /dev/null +++ b/patches/server/0627-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/0628-Entity-powdered-snow-API.patch b/patches/server/0628-Entity-powdered-snow-API.patch new file mode 100644 index 0000000000..acfaef73e3 --- /dev/null +++ b/patches/server/0628-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 b13c947d2cfe085017b30cb0f8340dd64f338914..442b5f13e976dd63bf1dccc12eb8c3f16314c581 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1095,6 +1095,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/0628-Improve-scoreboard-entries.patch b/patches/server/0628-Improve-scoreboard-entries.patch deleted file mode 100644 index 8acac86ce3..0000000000 --- a/patches/server/0628-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/0629-Add-API-for-item-entity-health.patch b/patches/server/0629-Add-API-for-item-entity-health.patch new file mode 100644 index 0000000000..cd2757b544 --- /dev/null +++ b/patches/server/0629-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/0629-Entity-powdered-snow-API.patch b/patches/server/0629-Entity-powdered-snow-API.patch deleted file mode 100644 index acfaef73e3..0000000000 --- a/patches/server/0629-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 b13c947d2cfe085017b30cb0f8340dd64f338914..442b5f13e976dd63bf1dccc12eb8c3f16314c581 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1095,6 +1095,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/0630-Add-API-for-item-entity-health.patch b/patches/server/0630-Add-API-for-item-entity-health.patch deleted file mode 100644 index cd2757b544..0000000000 --- a/patches/server/0630-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/0630-Configurable-max-block-light-for-monster-spawning.patch b/patches/server/0630-Configurable-max-block-light-for-monster-spawning.patch new file mode 100644 index 0000000000..8c19486a5f --- /dev/null +++ b/patches/server/0630-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/0631-Configurable-max-block-light-for-monster-spawning.patch b/patches/server/0631-Configurable-max-block-light-for-monster-spawning.patch deleted file mode 100644 index 8c19486a5f..0000000000 --- a/patches/server/0631-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/0631-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch b/patches/server/0631-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch new file mode 100644 index 0000000000..b239d74e25 --- /dev/null +++ b/patches/server/0631-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/0632-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch b/patches/server/0632-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch new file mode 100644 index 0000000000..cfaa295706 --- /dev/null +++ b/patches/server/0632-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/0632-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch b/patches/server/0632-Fix-sticky-pistons-and-BlockPistonRetractEvent.patch deleted file mode 100644 index b239d74e25..0000000000 --- a/patches/server/0632-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/0633-Bucketable-API.patch b/patches/server/0633-Bucketable-API.patch new file mode 100644 index 0000000000..274ccde059 --- /dev/null +++ b/patches/server/0633-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/0633-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch b/patches/server/0633-Expose-isFuel-and-canSmelt-methods-to-FurnaceInvento.patch deleted file mode 100644 index cfaa295706..0000000000 --- a/patches/server/0633-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/0634-Bucketable-API.patch b/patches/server/0634-Bucketable-API.patch deleted file mode 100644 index 274ccde059..0000000000 --- a/patches/server/0634-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/0634-Validate-usernames.patch b/patches/server/0634-Validate-usernames.patch new file mode 100644 index 0000000000..62c4153948 --- /dev/null +++ b/patches/server/0634-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 9419b073ac2d64d5dad4cefbcb90b4a928ef1dc2..5c18d08db9f65431a3d4f696691f16b29628fb84 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/0635-Make-water-animal-spawn-height-configurable.patch b/patches/server/0635-Make-water-animal-spawn-height-configurable.patch new file mode 100644 index 0000000000..341b55b1f6 --- /dev/null +++ b/patches/server/0635-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/0635-Validate-usernames.patch b/patches/server/0635-Validate-usernames.patch deleted file mode 100644 index 62c4153948..0000000000 --- a/patches/server/0635-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 9419b073ac2d64d5dad4cefbcb90b4a928ef1dc2..5c18d08db9f65431a3d4f696691f16b29628fb84 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/0636-Expose-vanilla-BiomeProvider-from-WorldInfo.patch b/patches/server/0636-Expose-vanilla-BiomeProvider-from-WorldInfo.patch new file mode 100644 index 0000000000..ae4199c5aa --- /dev/null +++ b/patches/server/0636-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 edd2e83df282b0e24d4c7e3a34776a5b039c2c6b..c133a646baf88e0489d358e302d67f21f76b47c3 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -625,7 +625,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 3ed78515fed78f5a679b9002e2e3a0aa6984aa70..8ca9a5d274a28f5feab492a446afea6b187b5d6a 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -363,7 +363,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 33d9f3778996eedc83064332a2fbbdc7c6a8ba90..62ab88e022230d25ffb359981ce7da4e64a9be5a 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 744e3631cd2d5c157c9b6023ca813e57c6f860d6..66778ebd82563823f692c7151f40a373e8d7427a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -209,6 +209,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/0636-Make-water-animal-spawn-height-configurable.patch b/patches/server/0636-Make-water-animal-spawn-height-configurable.patch deleted file mode 100644 index 341b55b1f6..0000000000 --- a/patches/server/0636-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/0637-Add-config-option-for-worlds-affected-by-time-cmd.patch b/patches/server/0637-Add-config-option-for-worlds-affected-by-time-cmd.patch new file mode 100644 index 0000000000..2146865230 --- /dev/null +++ b/patches/server/0637-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 ec4ea21f14f8dbf6a26b6124256386ff51c0628b..8b83d747de831878ff45dc74b4ae7cd9efb21d8c 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(); +@@ -75,7 +75,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/0637-Expose-vanilla-BiomeProvider-from-WorldInfo.patch b/patches/server/0637-Expose-vanilla-BiomeProvider-from-WorldInfo.patch deleted file mode 100644 index af63e382de..0000000000 --- a/patches/server/0637-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 edd2e83df282b0e24d4c7e3a34776a5b039c2c6b..c133a646baf88e0489d358e302d67f21f76b47c3 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -625,7 +625,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 3205ef2b0027a2fa7f9ba5ed3437f71f1c6e02b5..fda4b5f2b848b432138207eff9a77fed6aaf3805 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -363,7 +363,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 33d9f3778996eedc83064332a2fbbdc7c6a8ba90..62ab88e022230d25ffb359981ce7da4e64a9be5a 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 744e3631cd2d5c157c9b6023ca813e57c6f860d6..66778ebd82563823f692c7151f40a373e8d7427a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -209,6 +209,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/0638-Add-config-option-for-worlds-affected-by-time-cmd.patch b/patches/server/0638-Add-config-option-for-worlds-affected-by-time-cmd.patch deleted file mode 100644 index 2146865230..0000000000 --- a/patches/server/0638-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 ec4ea21f14f8dbf6a26b6124256386ff51c0628b..8b83d747de831878ff45dc74b4ae7cd9efb21d8c 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(); -@@ -75,7 +75,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/0638-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch b/patches/server/0638-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch new file mode 100644 index 0000000000..be0eedab93 --- /dev/null +++ b/patches/server/0638-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/0639-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch b/patches/server/0639-Add-missing-IAE-check-for-PersistentDataContainer-ha.patch deleted file mode 100644 index be0eedab93..0000000000 --- a/patches/server/0639-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/0639-Multiple-Entries-with-Scoreboards.patch b/patches/server/0639-Multiple-Entries-with-Scoreboards.patch new file mode 100644 index 0000000000..558cc93da5 --- /dev/null +++ b/patches/server/0639-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/0640-Multiple-Entries-with-Scoreboards.patch b/patches/server/0640-Multiple-Entries-with-Scoreboards.patch deleted file mode 100644 index 558cc93da5..0000000000 --- a/patches/server/0640-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/0640-Reset-placed-block-on-exception.patch b/patches/server/0640-Reset-placed-block-on-exception.patch new file mode 100644 index 0000000000..09609b372b --- /dev/null +++ b/patches/server/0640-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 2527fea68885c6911d01cd5a9b08a347d30844c8..cdd41eb371b1dd244a72c863cc5c8c4e84a9a71a 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/0641-Add-configurable-height-for-slime-spawn.patch b/patches/server/0641-Add-configurable-height-for-slime-spawn.patch new file mode 100644 index 0000000000..dfc8ecb349 --- /dev/null +++ b/patches/server/0641-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/0641-Reset-placed-block-on-exception.patch b/patches/server/0641-Reset-placed-block-on-exception.patch deleted file mode 100644 index 09609b372b..0000000000 --- a/patches/server/0641-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 2527fea68885c6911d01cd5a9b08a347d30844c8..cdd41eb371b1dd244a72c863cc5c8c4e84a9a71a 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/0642-Add-configurable-height-for-slime-spawn.patch b/patches/server/0642-Add-configurable-height-for-slime-spawn.patch deleted file mode 100644 index dfc8ecb349..0000000000 --- a/patches/server/0642-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/0642-Fix-xp-reward-for-baby-zombies.patch b/patches/server/0642-Fix-xp-reward-for-baby-zombies.patch new file mode 100644 index 0000000000..3ec320760f --- /dev/null +++ b/patches/server/0642-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/0643-Fix-xp-reward-for-baby-zombies.patch b/patches/server/0643-Fix-xp-reward-for-baby-zombies.patch deleted file mode 100644 index 3ec320760f..0000000000 --- a/patches/server/0643-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/0643-Multi-Block-Change-API-Implementation.patch b/patches/server/0643-Multi-Block-Change-API-Implementation.patch new file mode 100644 index 0000000000..ae2c0b83d4 --- /dev/null +++ b/patches/server/0643-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 f363f885b3dc1852b09914f034740794e3025d3d..eb48efa038043dacf539811de9e0f0faa1ec6b42 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -937,6 +937,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/0644-Fix-NotePlayEvent.patch b/patches/server/0644-Fix-NotePlayEvent.patch new file mode 100644 index 0000000000..cdffcd6f0f --- /dev/null +++ b/patches/server/0644-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/0644-Multi-Block-Change-API-Implementation.patch b/patches/server/0644-Multi-Block-Change-API-Implementation.patch deleted file mode 100644 index ae2c0b83d4..0000000000 --- a/patches/server/0644-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 f363f885b3dc1852b09914f034740794e3025d3d..eb48efa038043dacf539811de9e0f0faa1ec6b42 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -937,6 +937,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/0645-Fix-NotePlayEvent.patch b/patches/server/0645-Fix-NotePlayEvent.patch deleted file mode 100644 index cdffcd6f0f..0000000000 --- a/patches/server/0645-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/0645-Freeze-Tick-Lock-API.patch b/patches/server/0645-Freeze-Tick-Lock-API.patch new file mode 100644 index 0000000000..4a4f993639 --- /dev/null +++ b/patches/server/0645-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 46884e4d6b7c434d58bd2f7e7e27cfcdcd0e2065..405911682f96fc54e7146333474f7d470b24035f 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -415,6 +415,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(); +@@ -764,7 +765,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); + } +@@ -2452,6 +2453,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) { +@@ -2599,6 +2603,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 d46886a658c5058ba2c622daff96f5daf15ef3f3..77fc3086d5848fddf62f301bb4a2dfdaed8b3c3c 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3621,7 +3621,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 442b5f13e976dd63bf1dccc12eb8c3f16314c581..10fb64df10820974d11f142c102a11a5bd0f317c 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/0646-Freeze-Tick-Lock-API.patch b/patches/server/0646-Freeze-Tick-Lock-API.patch deleted file mode 100644 index 7738c9a43c..0000000000 --- a/patches/server/0646-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 68b072415d312e22ef00da3689efcd4631934163..05a105cfc59bad7ca8fdf2355c6338cdff446d6a 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -415,6 +415,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(); -@@ -764,7 +765,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); - } -@@ -2452,6 +2453,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) { -@@ -2599,6 +2603,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 d46886a658c5058ba2c622daff96f5daf15ef3f3..77fc3086d5848fddf62f301bb4a2dfdaed8b3c3c 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3621,7 +3621,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 442b5f13e976dd63bf1dccc12eb8c3f16314c581..10fb64df10820974d11f142c102a11a5bd0f317c 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/0646-More-PotionEffectType-API.patch b/patches/server/0646-More-PotionEffectType-API.patch new file mode 100644 index 0000000000..2773c98338 --- /dev/null +++ b/patches/server/0646-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/0647-More-PotionEffectType-API.patch b/patches/server/0647-More-PotionEffectType-API.patch deleted file mode 100644 index 2773c98338..0000000000 --- a/patches/server/0647-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/0647-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch b/patches/server/0647-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch new file mode 100644 index 0000000000..027285c2b1 --- /dev/null +++ b/patches/server/0647-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/0648-API-for-creating-command-sender-which-forwards-feedb.patch b/patches/server/0648-API-for-creating-command-sender-which-forwards-feedb.patch new file mode 100644 index 0000000000..f86274766d --- /dev/null +++ b/patches/server/0648-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 62ab88e022230d25ffb359981ce7da4e64a9be5a..3b01907bc119853e0676e912e9a29b05d9aa5763 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 35b05f9321ddbbbdf62f4bf726b58cf1205f0cfb..ce8683eff5b8ade57a2fcb77027cfe4b26986bc7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +@@ -86,6 +86,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/0648-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch b/patches/server/0648-Use-a-CHM-for-StructureTemplate.Pallete-cache.patch deleted file mode 100644 index 027285c2b1..0000000000 --- a/patches/server/0648-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/0649-API-for-creating-command-sender-which-forwards-feedb.patch b/patches/server/0649-API-for-creating-command-sender-which-forwards-feedb.patch deleted file mode 100644 index f86274766d..0000000000 --- a/patches/server/0649-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 62ab88e022230d25ffb359981ce7da4e64a9be5a..3b01907bc119853e0676e912e9a29b05d9aa5763 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 35b05f9321ddbbbdf62f4bf726b58cf1205f0cfb..ce8683eff5b8ade57a2fcb77027cfe4b26986bc7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java -@@ -86,6 +86,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/0649-Add-missing-structure-set-seed-configs.patch b/patches/server/0649-Add-missing-structure-set-seed-configs.patch new file mode 100644 index 0000000000..e2dfe31280 --- /dev/null +++ b/patches/server/0649-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 fde17b4e2607fc443a33aea3a631aae6ccb71e2c..c64389acf0764c8d048bea2d99a21a0da832150d 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -574,7 +574,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, dimension); + } 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/0650-Add-missing-structure-set-seed-configs.patch b/patches/server/0650-Add-missing-structure-set-seed-configs.patch deleted file mode 100644 index e2dfe31280..0000000000 --- a/patches/server/0650-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 fde17b4e2607fc443a33aea3a631aae6ccb71e2c..c64389acf0764c8d048bea2d99a21a0da832150d 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -574,7 +574,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, dimension); - } 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/0650-Fix-cancelled-powdered-snow-bucket-placement.patch b/patches/server/0650-Fix-cancelled-powdered-snow-bucket-placement.patch new file mode 100644 index 0000000000..f07f56f707 --- /dev/null +++ b/patches/server/0650-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 e320264c2283c2c09910ea70606413c73f443b1f..18f84d54ec72debec652adb22067e11aa058b238 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -430,7 +430,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) { +@@ -493,7 +493,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/0651-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch b/patches/server/0651-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch new file mode 100644 index 0000000000..d5922672e4 --- /dev/null +++ b/patches/server/0651-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 3b01907bc119853e0676e912e9a29b05d9aa5763..188e3066d6659b5e45cec0b50dcbd5d20659830a 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/0651-Fix-cancelled-powdered-snow-bucket-placement.patch b/patches/server/0651-Fix-cancelled-powdered-snow-bucket-placement.patch deleted file mode 100644 index f07f56f707..0000000000 --- a/patches/server/0651-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 e320264c2283c2c09910ea70606413c73f443b1f..18f84d54ec72debec652adb22067e11aa058b238 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -430,7 +430,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) { -@@ -493,7 +493,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/0652-Add-GameEvent-tags.patch b/patches/server/0652-Add-GameEvent-tags.patch new file mode 100644 index 0000000000..bb674d2f17 --- /dev/null +++ b/patches/server/0652-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 188e3066d6659b5e45cec0b50dcbd5d20659830a..72f8d3a89396f9289f5b451b24cc181e7ac3222e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2709,6 +2709,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(); + } + +@@ -2746,6 +2755,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/0652-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch b/patches/server/0652-Add-missing-Validate-calls-to-CraftServer-getSpawnLi.patch deleted file mode 100644 index d5922672e4..0000000000 --- a/patches/server/0652-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 3b01907bc119853e0676e912e9a29b05d9aa5763..188e3066d6659b5e45cec0b50dcbd5d20659830a 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/0653-Add-GameEvent-tags.patch b/patches/server/0653-Add-GameEvent-tags.patch deleted file mode 100644 index bb674d2f17..0000000000 --- a/patches/server/0653-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 188e3066d6659b5e45cec0b50dcbd5d20659830a..72f8d3a89396f9289f5b451b24cc181e7ac3222e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2709,6 +2709,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(); - } - -@@ -2746,6 +2755,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/0653-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch b/patches/server/0653-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch new file mode 100644 index 0000000000..5929e0f042 --- /dev/null +++ b/patches/server/0653-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 c133a646baf88e0489d358e302d67f21f76b47c3..17700ebf508f3ac7a4d1cdd8d52355afaf5d006f 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1404,6 +1404,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 c133a646baf88e0489d358e302d67f21f76b47c3..17700ebf508f3ac7a4d1cdd8d52355afaf5d006f 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1404,6 +1404,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 fd2f28ee785283bcc979c7a146308827f2ce2ba9..91c10f7d2044d60ba756179d93c5c72d32bba074 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/0655-Configurable-sculk-sensor-listener-range.patch b/patches/server/0655-Configurable-sculk-sensor-listener-range.patch new file mode 100644 index 0000000000..3dd1324354 --- /dev/null +++ b/patches/server/0655-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/0655-Furnace-RecipesUsed-API.patch b/patches/server/0655-Furnace-RecipesUsed-API.patch deleted file mode 100644 index f2b8d8fe65..0000000000 --- a/patches/server/0655-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 fd2f28ee785283bcc979c7a146308827f2ce2ba9..91c10f7d2044d60ba756179d93c5c72d32bba074 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/0656-Add-missing-block-data-API.patch b/patches/server/0656-Add-missing-block-data-API.patch new file mode 100644 index 0000000000..7c18d0cb0d --- /dev/null +++ b/patches/server/0656-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/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/CraftParticleLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftParticleLeaves.java +index db4849a35d34da4ab42bbe7569c4944ed95d8f2b..e37e84c333a42006b6c32cf5cd71c0bbfa725141 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftParticleLeaves.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftParticleLeaves.java +@@ -51,4 +51,16 @@ public final class CraftParticleLeaves extends org.bukkit.craftbukkit.block.data + public void setWaterlogged(boolean waterlogged) { + this.set(CraftParticleLeaves.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/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/0656-Configurable-sculk-sensor-listener-range.patch b/patches/server/0656-Configurable-sculk-sensor-listener-range.patch deleted file mode 100644 index 3dd1324354..0000000000 --- a/patches/server/0656-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/0657-Add-missing-block-data-API.patch b/patches/server/0657-Add-missing-block-data-API.patch deleted file mode 100644 index 7c18d0cb0d..0000000000 --- a/patches/server/0657-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/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/CraftParticleLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftParticleLeaves.java -index db4849a35d34da4ab42bbe7569c4944ed95d8f2b..e37e84c333a42006b6c32cf5cd71c0bbfa725141 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftParticleLeaves.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftParticleLeaves.java -@@ -51,4 +51,16 @@ public final class CraftParticleLeaves extends org.bukkit.craftbukkit.block.data - public void setWaterlogged(boolean waterlogged) { - this.set(CraftParticleLeaves.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/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/0657-Option-to-have-default-CustomSpawners-in-custom-worl.patch b/patches/server/0657-Option-to-have-default-CustomSpawners-in-custom-worl.patch new file mode 100644 index 0000000000..69da29074a --- /dev/null +++ b/patches/server/0657-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 17700ebf508f3ac7a4d1cdd8d52355afaf5d006f..64dce8d94cf261113d6f8b99020bf710b9762c2b 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -645,7 +645,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/0658-Option-to-have-default-CustomSpawners-in-custom-worl.patch b/patches/server/0658-Option-to-have-default-CustomSpawners-in-custom-worl.patch deleted file mode 100644 index 69da29074a..0000000000 --- a/patches/server/0658-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 17700ebf508f3ac7a4d1cdd8d52355afaf5d006f..64dce8d94cf261113d6f8b99020bf710b9762c2b 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -645,7 +645,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/0658-Put-world-into-worldlist-before-initing-the-world.patch b/patches/server/0658-Put-world-into-worldlist-before-initing-the-world.patch new file mode 100644 index 0000000000..ffe26b0b55 --- /dev/null +++ b/patches/server/0658-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 64dce8d94cf261113d6f8b99020bf710b9762c2b..03ee72a20330dd9ba6ff2808c1252454a6c217bc 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -657,9 +657,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 03ee72a20330dd9ba6ff2808c1252454a6c217bc..fcc00d5b0be3d2adb92c8243ccca8d0190fcc413 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 75bd9617164c63a641602bf772a5e0f15a322c7e..82e1c4713e043c4903b1f0154609da4558f90aef 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 + } + +@@ -3076,5 +3078,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 fa47232eeb36ed92b5a526bb00398f08b6c0ab41..5b176cd5f80a49e3a2afbcbf4fe2958143719bce 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java +@@ -23,6 +23,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/0659-Put-world-into-worldlist-before-initing-the-world.patch b/patches/server/0659-Put-world-into-worldlist-before-initing-the-world.patch deleted file mode 100644 index ffe26b0b55..0000000000 --- a/patches/server/0659-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 64dce8d94cf261113d6f8b99020bf710b9762c2b..03ee72a20330dd9ba6ff2808c1252454a6c217bc 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -657,9 +657,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 03ee72a20330dd9ba6ff2808c1252454a6c217bc..fcc00d5b0be3d2adb92c8243ccca8d0190fcc413 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 75bd9617164c63a641602bf772a5e0f15a322c7e..82e1c4713e043c4903b1f0154609da4558f90aef 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 - } - -@@ -3076,5 +3078,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 fa47232eeb36ed92b5a526bb00398f08b6c0ab41..5b176cd5f80a49e3a2afbcbf4fe2958143719bce 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java -@@ -23,6 +23,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/0660-Force-close-world-loading-screen.patch b/patches/server/0660-Force-close-world-loading-screen.patch new file mode 100644 index 0000000000..f609c7e093 --- /dev/null +++ b/patches/server/0660-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 5c18d08db9f65431a3d4f696691f16b29628fb84..34a9e57e4fa5318ec25f1308ae1156705d688d5f 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/0661-Fix-falling-block-spawn-methods.patch b/patches/server/0661-Fix-falling-block-spawn-methods.patch new file mode 100644 index 0000000000..9703a17436 --- /dev/null +++ b/patches/server/0661-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 66778ebd82563823f692c7151f40a373e8d7427a..827cf8b2e241e49dac961b103f32546a04f8a2f9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1386,7 +1386,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(); + } + +@@ -1395,7 +1400,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 95c2ef53e6c5574e69614d8058eb3ed94ab6b0d6..f3ad9c57ce2fc06b90b7ab7e1f31ef0e1b564c9f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -438,7 +438,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/0661-Force-close-world-loading-screen.patch b/patches/server/0661-Force-close-world-loading-screen.patch deleted file mode 100644 index f609c7e093..0000000000 --- a/patches/server/0661-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 5c18d08db9f65431a3d4f696691f16b29628fb84..34a9e57e4fa5318ec25f1308ae1156705d688d5f 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/0662-Expose-furnace-minecart-push-values.patch b/patches/server/0662-Expose-furnace-minecart-push-values.patch new file mode 100644 index 0000000000..fb48aabb5f --- /dev/null +++ b/patches/server/0662-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/0662-Fix-falling-block-spawn-methods.patch b/patches/server/0662-Fix-falling-block-spawn-methods.patch deleted file mode 100644 index 9703a17436..0000000000 --- a/patches/server/0662-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 66778ebd82563823f692c7151f40a373e8d7427a..827cf8b2e241e49dac961b103f32546a04f8a2f9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1386,7 +1386,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(); - } - -@@ -1395,7 +1400,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 95c2ef53e6c5574e69614d8058eb3ed94ab6b0d6..f3ad9c57ce2fc06b90b7ab7e1f31ef0e1b564c9f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -438,7 +438,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/0663-Expose-furnace-minecart-push-values.patch b/patches/server/0663-Expose-furnace-minecart-push-values.patch deleted file mode 100644 index fb48aabb5f..0000000000 --- a/patches/server/0663-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/0663-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch b/patches/server/0663-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch new file mode 100644 index 0000000000..b6a532242d --- /dev/null +++ b/patches/server/0663-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 320ace815df1a76232df53d5ddeb3aef9b358d8e..758fa49f9b420fdbb583ca3443b81ca151478ea8 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -345,6 +345,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/0664-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch b/patches/server/0664-Fix-cancelling-ProjectileHitEvent-for-piercing-arrow.patch deleted file mode 100644 index c98e7fd0f3..0000000000 --- a/patches/server/0664-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 aab7d546317d93876ccd0e02c0631ccc7c8f9bf5..0abe2fe6d7cf0a2084b7219c3ab0c5118586a8fe 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -345,6 +345,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/0664-More-Projectile-API.patch b/patches/server/0664-More-Projectile-API.patch new file mode 100644 index 0000000000..8f77d7deb8 --- /dev/null +++ b/patches/server/0664-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 966ba1a9c2e7923a970ce3799a5e2ef6ca36bf84..a2487ca0d7794e58d9ede35d9be5a05a7ea7b03c 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 5cff58ab33657e7fb2642928e42b728e7b0b4689..f3781e37358f970b56e5b8de77ef224151270f1c 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 f3ad9c57ce2fc06b90b7ab7e1f31ef0e1b564c9f..2a32f2aa3cb7395900cf2d06cc2dcd4ddacd4145 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 { + 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 10a95c1a40597867ffd2974037bfed86dd6deda4..9399df20ba14ad92379d5d2048e249883eaa8050 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.PROJECTILE_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 a5285a8952b2d99bfbb928b1bb31d3ddcf8ed57b..ca094e393de32b64db59c9fe906433761d70d29b 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/0665-Fix-swamp-hut-cat-generation-deadlock.patch b/patches/server/0665-Fix-swamp-hut-cat-generation-deadlock.patch new file mode 100644 index 0000000000..ed87313991 --- /dev/null +++ b/patches/server/0665-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 93d8d45a9a8108e58f3a96d77dd35c7584133835..629b282cf27806ff37d67f83d44c06a9f32a9185 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java +@@ -365,7 +365,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/0665-More-Projectile-API.patch b/patches/server/0665-More-Projectile-API.patch deleted file mode 100644 index 8f77d7deb8..0000000000 --- a/patches/server/0665-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 966ba1a9c2e7923a970ce3799a5e2ef6ca36bf84..a2487ca0d7794e58d9ede35d9be5a05a7ea7b03c 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 5cff58ab33657e7fb2642928e42b728e7b0b4689..f3781e37358f970b56e5b8de77ef224151270f1c 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 f3ad9c57ce2fc06b90b7ab7e1f31ef0e1b564c9f..2a32f2aa3cb7395900cf2d06cc2dcd4ddacd4145 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 { - 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 10a95c1a40597867ffd2974037bfed86dd6deda4..9399df20ba14ad92379d5d2048e249883eaa8050 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.PROJECTILE_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 a5285a8952b2d99bfbb928b1bb31d3ddcf8ed57b..ca094e393de32b64db59c9fe906433761d70d29b 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/0666-Don-t-allow-vehicle-movement-from-players-while-tele.patch b/patches/server/0666-Don-t-allow-vehicle-movement-from-players-while-tele.patch new file mode 100644 index 0000000000..7ccbeb4b00 --- /dev/null +++ b/patches/server/0666-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 88ba98aee07764e418edb9052075acea557ceec9..864ab4d3de50ee9ce9ff2b0538aa46df43985a84 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -491,6 +491,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() && this.player.hasClientLoaded()) { + 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/0666-Fix-swamp-hut-cat-generation-deadlock.patch b/patches/server/0666-Fix-swamp-hut-cat-generation-deadlock.patch deleted file mode 100644 index ed87313991..0000000000 --- a/patches/server/0666-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 93d8d45a9a8108e58f3a96d77dd35c7584133835..629b282cf27806ff37d67f83d44c06a9f32a9185 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -365,7 +365,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/0667-Don-t-allow-vehicle-movement-from-players-while-tele.patch b/patches/server/0667-Don-t-allow-vehicle-movement-from-players-while-tele.patch deleted file mode 100644 index 7ccbeb4b00..0000000000 --- a/patches/server/0667-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 88ba98aee07764e418edb9052075acea557ceec9..864ab4d3de50ee9ce9ff2b0538aa46df43985a84 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -491,6 +491,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() && this.player.hasClientLoaded()) { - 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/0667-Implement-getComputedBiome-API.patch b/patches/server/0667-Implement-getComputedBiome-API.patch new file mode 100644 index 0000000000..dab55a6218 --- /dev/null +++ b/patches/server/0667-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/0668-Implement-getComputedBiome-API.patch b/patches/server/0668-Implement-getComputedBiome-API.patch deleted file mode 100644 index dab55a6218..0000000000 --- a/patches/server/0668-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/0668-Make-some-itemstacks-nonnull.patch b/patches/server/0668-Make-some-itemstacks-nonnull.patch new file mode 100644 index 0000000000..20944d9088 --- /dev/null +++ b/patches/server/0668-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/0669-Implement-enchantWithLevels-API.patch b/patches/server/0669-Implement-enchantWithLevels-API.patch new file mode 100644 index 0000000000..008d6aaf29 --- /dev/null +++ b/patches/server/0669-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 a04840b77e2d84e754c9cfa79bc593608bc22c90..6d228d643342588877e8385acdc202de57d455f1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +@@ -307,4 +307,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/0669-Make-some-itemstacks-nonnull.patch b/patches/server/0669-Make-some-itemstacks-nonnull.patch deleted file mode 100644 index 20944d9088..0000000000 --- a/patches/server/0669-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/0670-Fix-saving-in-unloadWorld.patch b/patches/server/0670-Fix-saving-in-unloadWorld.patch new file mode 100644 index 0000000000..540896076f --- /dev/null +++ b/patches/server/0670-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 82e1c4713e043c4903b1f0154609da4558f90aef..430b35c35c7aa17d590031515063f2d24eeffe5c 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/0670-Implement-enchantWithLevels-API.patch b/patches/server/0670-Implement-enchantWithLevels-API.patch deleted file mode 100644 index 008d6aaf29..0000000000 --- a/patches/server/0670-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 a04840b77e2d84e754c9cfa79bc593608bc22c90..6d228d643342588877e8385acdc202de57d455f1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java -@@ -307,4 +307,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/0671-Buffer-OOB-setBlock-calls.patch b/patches/server/0671-Buffer-OOB-setBlock-calls.patch new file mode 100644 index 0000000000..1b7ba291c4 --- /dev/null +++ b/patches/server/0671-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/0671-Fix-saving-in-unloadWorld.patch b/patches/server/0671-Fix-saving-in-unloadWorld.patch deleted file mode 100644 index 540896076f..0000000000 --- a/patches/server/0671-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 82e1c4713e043c4903b1f0154609da4558f90aef..430b35c35c7aa17d590031515063f2d24eeffe5c 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/0672-Add-TameableDeathMessageEvent.patch b/patches/server/0672-Add-TameableDeathMessageEvent.patch new file mode 100644 index 0000000000..85016be93d --- /dev/null +++ b/patches/server/0672-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 45a340fddcec48dfb796f4515a500452adb30c59..1c195c928fb5c165981665393424a64004331c93 100644 +--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +@@ -257,7 +257,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/0672-Buffer-OOB-setBlock-calls.patch b/patches/server/0672-Buffer-OOB-setBlock-calls.patch deleted file mode 100644 index 1b7ba291c4..0000000000 --- a/patches/server/0672-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/0673-Add-TameableDeathMessageEvent.patch b/patches/server/0673-Add-TameableDeathMessageEvent.patch deleted file mode 100644 index 85016be93d..0000000000 --- a/patches/server/0673-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 45a340fddcec48dfb796f4515a500452adb30c59..1c195c928fb5c165981665393424a64004331c93 100644 ---- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -@@ -257,7 +257,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/0673-Fix-new-block-data-for-EntityChangeBlockEvent.patch b/patches/server/0673-Fix-new-block-data-for-EntityChangeBlockEvent.patch new file mode 100644 index 0000000000..fd2ea22a5e --- /dev/null +++ b/patches/server/0673-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 cfda434358a2e14ebd6cc10609c599f6d65bb6ef..53d60d62686f9b6bc98b6b25e4315b848600a99d 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 8415f7e1f8c391961dc5b0669da1ab4f8ae4950d..fa8c7a7f71621437bec2ce69c3ad24b495ceed1d 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 +@@ -374,7 +374,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 4b798695af365dc97cbbbd09f370b8fc425f9ed6..2a394381a4ad46359359ba402b65c62b331480b4 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +@@ -551,7 +551,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 772476d44ee72aed1ba35d10fe51f0ffda34d3f8..cfc28828a5b81563a826ae6045553e7350f67986 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java +@@ -162,7 +162,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 ca094e393de32b64db59c9fe906433761d70d29b..fcc9fe8f5f57e9f6c28d762aa6585942e2b2698b 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/0674-Fix-new-block-data-for-EntityChangeBlockEvent.patch b/patches/server/0674-Fix-new-block-data-for-EntityChangeBlockEvent.patch deleted file mode 100644 index fd2ea22a5e..0000000000 --- a/patches/server/0674-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 cfda434358a2e14ebd6cc10609c599f6d65bb6ef..53d60d62686f9b6bc98b6b25e4315b848600a99d 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 8415f7e1f8c391961dc5b0669da1ab4f8ae4950d..fa8c7a7f71621437bec2ce69c3ad24b495ceed1d 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 -@@ -374,7 +374,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 4b798695af365dc97cbbbd09f370b8fc425f9ed6..2a394381a4ad46359359ba402b65c62b331480b4 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -551,7 +551,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 772476d44ee72aed1ba35d10fe51f0ffda34d3f8..cfc28828a5b81563a826ae6045553e7350f67986 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -162,7 +162,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 ca094e393de32b64db59c9fe906433761d70d29b..fcc9fe8f5f57e9f6c28d762aa6585942e2b2698b 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/0674-fix-player-loottables-running-when-mob-loot-gamerule.patch b/patches/server/0674-fix-player-loottables-running-when-mob-loot-gamerule.patch new file mode 100644 index 0000000000..a858720f1e --- /dev/null +++ b/patches/server/0674-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 0efd5d23924efec5e2bff0c7b3dddb6e97723e29..ed8a1457b99f862762e49c84db2585ce410f278a 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1215,12 +1215,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/0675-Ensure-entity-passenger-world-matches-ridden-entity.patch b/patches/server/0675-Ensure-entity-passenger-world-matches-ridden-entity.patch new file mode 100644 index 0000000000..43c04c7c05 --- /dev/null +++ b/patches/server/0675-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 405911682f96fc54e7146333474f7d470b24035f..d078f48a7652a2e01984329ccf8301daa7ec4c38 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2833,7 +2833,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/0675-fix-player-loottables-running-when-mob-loot-gamerule.patch b/patches/server/0675-fix-player-loottables-running-when-mob-loot-gamerule.patch deleted file mode 100644 index 2bc0c5993d..0000000000 --- a/patches/server/0675-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 e2a8e0291a5c0c00d7d6135a0d34fb8bab7b4cd5..15158bec7e2ca90b45347ba09cf17f25e919f9cf 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1215,12 +1215,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/0676-Cache-resource-keys-and-optimize-reference-Holder-ta.patch b/patches/server/0676-Cache-resource-keys-and-optimize-reference-Holder-ta.patch new file mode 100644 index 0000000000..7356aca21a --- /dev/null +++ b/patches/server/0676-Cache-resource-keys-and-optimize-reference-Holder-ta.patch @@ -0,0 +1,38 @@ +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/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/0676-Ensure-entity-passenger-world-matches-ridden-entity.patch b/patches/server/0676-Ensure-entity-passenger-world-matches-ridden-entity.patch deleted file mode 100644 index 78807f6d4c..0000000000 --- a/patches/server/0676-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 05a105cfc59bad7ca8fdf2355c6338cdff446d6a..8cf1a2a4dbf1d26d17dc5b4f67a52f7df54dae81 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2833,7 +2833,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/0677-Allow-changing-the-EnderDragon-podium.patch b/patches/server/0677-Allow-changing-the-EnderDragon-podium.patch new file mode 100644 index 0000000000..0676f66fd1 --- /dev/null +++ b/patches/server/0677-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 f5aee15f80e226c8d59e66b1a53f529e2fb524a5..037b261a40a800f6d5e9ecd22e230d030b797958 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); +@@ -1002,7 +1019,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/0677-Cache-resource-keys-and-optimize-reference-Holder-ta.patch b/patches/server/0677-Cache-resource-keys-and-optimize-reference-Holder-ta.patch deleted file mode 100644 index 7356aca21a..0000000000 --- a/patches/server/0677-Cache-resource-keys-and-optimize-reference-Holder-ta.patch +++ /dev/null @@ -1,38 +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/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/0678-Allow-changing-the-EnderDragon-podium.patch b/patches/server/0678-Allow-changing-the-EnderDragon-podium.patch deleted file mode 100644 index 0676f66fd1..0000000000 --- a/patches/server/0678-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 f5aee15f80e226c8d59e66b1a53f529e2fb524a5..037b261a40a800f6d5e9ecd22e230d030b797958 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); -@@ -1002,7 +1019,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/0678-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch b/patches/server/0678-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch new file mode 100644 index 0000000000..f885dbe8b4 --- /dev/null +++ b/patches/server/0678-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/0679-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch b/patches/server/0679-Fix-NBT-pieces-overriding-a-block-entity-during-worl.patch deleted file mode 100644 index f885dbe8b4..0000000000 --- a/patches/server/0679-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/0679-Use-username-instead-of-display-name-in-PlayerList-g.patch b/patches/server/0679-Use-username-instead-of-display-name-in-PlayerList-g.patch new file mode 100644 index 0000000000..7ba2f534fa --- /dev/null +++ b/patches/server/0679-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 34a9e57e4fa5318ec25f1308ae1156705d688d5f..91a3b9866e02414d2d71aa53ef1fb5fdecd8cd89 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -1353,7 +1353,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/0680-Expand-PlayerItemDamageEvent.patch b/patches/server/0680-Expand-PlayerItemDamageEvent.patch new file mode 100644 index 0000000000..85a05db466 --- /dev/null +++ b/patches/server/0680-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 18f84d54ec72debec652adb22067e11aa058b238..679112d1622744680b7d3c7d296acafac019d00a 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -698,10 +698,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/0680-Use-username-instead-of-display-name-in-PlayerList-g.patch b/patches/server/0680-Use-username-instead-of-display-name-in-PlayerList-g.patch deleted file mode 100644 index 7ba2f534fa..0000000000 --- a/patches/server/0680-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 34a9e57e4fa5318ec25f1308ae1156705d688d5f..91a3b9866e02414d2d71aa53ef1fb5fdecd8cd89 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1353,7 +1353,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/0681-Expand-PlayerItemDamageEvent.patch b/patches/server/0681-Expand-PlayerItemDamageEvent.patch deleted file mode 100644 index 85a05db466..0000000000 --- a/patches/server/0681-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 18f84d54ec72debec652adb22067e11aa058b238..679112d1622744680b7d3c7d296acafac019d00a 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -698,10 +698,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/0681-WorldCreator-keepSpawnLoaded.patch b/patches/server/0681-WorldCreator-keepSpawnLoaded.patch new file mode 100644 index 0000000000..ab38fc7006 --- /dev/null +++ b/patches/server/0681-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 430b35c35c7aa17d590031515063f2d24eeffe5c..4b894223387bf4029bbfa15d9605247935d7f829 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/0682-Fix-CME-in-CraftPersistentDataTypeRegistry.patch b/patches/server/0682-Fix-CME-in-CraftPersistentDataTypeRegistry.patch new file mode 100644 index 0000000000..ed8adb4503 --- /dev/null +++ b/patches/server/0682-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/0682-WorldCreator-keepSpawnLoaded.patch b/patches/server/0682-WorldCreator-keepSpawnLoaded.patch deleted file mode 100644 index ab38fc7006..0000000000 --- a/patches/server/0682-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 430b35c35c7aa17d590031515063f2d24eeffe5c..4b894223387bf4029bbfa15d9605247935d7f829 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/0683-Fix-CME-in-CraftPersistentDataTypeRegistry.patch b/patches/server/0683-Fix-CME-in-CraftPersistentDataTypeRegistry.patch deleted file mode 100644 index ed8adb4503..0000000000 --- a/patches/server/0683-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/0683-Trigger-bee_nest_destroyed-trigger-in-the-correct-pl.patch b/patches/server/0683-Trigger-bee_nest_destroyed-trigger-in-the-correct-pl.patch new file mode 100644 index 0000000000..105d2132f3 --- /dev/null +++ b/patches/server/0683-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 4ec03b15bb8a82d92fcb2b7fef70e3c7087a9b68..3e3951cbb196b720256cfc36d6d3b91d48ce3294 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/0684-Add-EntityDyeEvent-and-CollarColorable-interface.patch b/patches/server/0684-Add-EntityDyeEvent-and-CollarColorable-interface.patch new file mode 100644 index 0000000000..79ada84e8b --- /dev/null +++ b/patches/server/0684-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 629b282cf27806ff37d67f83d44c06a9f32a9185..9a67dfe214d3eb89d1f4371e716df759651ceb1b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java +@@ -386,6 +386,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 4ec03b15bb8a82d92fcb2b7fef70e3c7087a9b68..3e3951cbb196b720256cfc36d6d3b91d48ce3294 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/0685-Add-EntityDyeEvent-and-CollarColorable-interface.patch b/patches/server/0685-Add-EntityDyeEvent-and-CollarColorable-interface.patch deleted file mode 100644 index 79ada84e8b..0000000000 --- a/patches/server/0685-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 629b282cf27806ff37d67f83d44c06a9f32a9185..9a67dfe214d3eb89d1f4371e716df759651ceb1b 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -386,6 +386,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/0686-Fire-CauldronLevelChange-on-initial-fill.patch b/patches/server/0686-Fire-CauldronLevelChange-on-initial-fill.patch deleted file mode 100644 index 86520e0647..0000000000 --- a/patches/server/0686-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/0686-fix-powder-snow-cauldrons-not-turning-to-water.patch b/patches/server/0686-fix-powder-snow-cauldrons-not-turning-to-water.patch new file mode 100644 index 0000000000..201c323a35 --- /dev/null +++ b/patches/server/0686-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/0687-Add-PlayerStopUsingItemEvent.patch b/patches/server/0687-Add-PlayerStopUsingItemEvent.patch new file mode 100644 index 0000000000..c787da04da --- /dev/null +++ b/patches/server/0687-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 77fc3086d5848fddf62f301bb4a2dfdaed8b3c3c..91fc54b060d8ab5d8e60a09677afbe1b46798064 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -4210,6 +4210,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/0687-fix-powder-snow-cauldrons-not-turning-to-water.patch b/patches/server/0687-fix-powder-snow-cauldrons-not-turning-to-water.patch deleted file mode 100644 index 201c323a35..0000000000 --- a/patches/server/0687-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/0688-Add-PlayerStopUsingItemEvent.patch b/patches/server/0688-Add-PlayerStopUsingItemEvent.patch deleted file mode 100644 index c787da04da..0000000000 --- a/patches/server/0688-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 77fc3086d5848fddf62f301bb4a2dfdaed8b3c3c..91fc54b060d8ab5d8e60a09677afbe1b46798064 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -4210,6 +4210,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/0688-Don-t-tick-markers.patch b/patches/server/0688-Don-t-tick-markers.patch new file mode 100644 index 0000000000..64875a4975 --- /dev/null +++ b/patches/server/0688-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 9d9d133e0d973ecda1ef1efc872a51ee10463fd1..f671b74e4179fc29bc600b52e456ba9f78d8bbd6 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 (!world.isPositionEntityTicking(e.blockPosition())) { ++ if (!world.isPositionEntityTicking(e.blockPosition()) || (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 8ca9a5d274a28f5feab492a446afea6b187b5d6a..ee0459e37b817648e37b1ea84a3edf7c52d00855 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2234,6 +2234,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/0689-Don-t-tick-markers.patch b/patches/server/0689-Don-t-tick-markers.patch deleted file mode 100644 index 64875a4975..0000000000 --- a/patches/server/0689-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 9d9d133e0d973ecda1ef1efc872a51ee10463fd1..f671b74e4179fc29bc600b52e456ba9f78d8bbd6 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 (!world.isPositionEntityTicking(e.blockPosition())) { -+ if (!world.isPositionEntityTicking(e.blockPosition()) || (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 8ca9a5d274a28f5feab492a446afea6b187b5d6a..ee0459e37b817648e37b1ea84a3edf7c52d00855 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2234,6 +2234,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/0689-Expand-FallingBlock-API.patch b/patches/server/0689-Expand-FallingBlock-API.patch new file mode 100644 index 0000000000..789dd54c78 --- /dev/null +++ b/patches/server/0689-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 eb1745915190e69bb467fca2dbc46e0727530ba0..692d78bff5f7f01c8545e0e1785953ccc0f00e2d 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/0690-Add-support-for-Proxy-Protocol.patch b/patches/server/0690-Add-support-for-Proxy-Protocol.patch new file mode 100644 index 0000000000..6c7cf55fb0 --- /dev/null +++ b/patches/server/0690-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 cc0a3c29aeb67e486fb75c1d6cc280192421c7cd..d79040747ec4dfddc866f0ad36d8423db957e98d 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -42,6 +42,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.24.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/0690-Expand-FallingBlock-API.patch b/patches/server/0690-Expand-FallingBlock-API.patch deleted file mode 100644 index 789dd54c78..0000000000 --- a/patches/server/0690-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 eb1745915190e69bb467fca2dbc46e0727530ba0..692d78bff5f7f01c8545e0e1785953ccc0f00e2d 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/0691-Add-support-for-Proxy-Protocol.patch b/patches/server/0691-Add-support-for-Proxy-Protocol.patch deleted file mode 100644 index 6c7cf55fb0..0000000000 --- a/patches/server/0691-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 cc0a3c29aeb67e486fb75c1d6cc280192421c7cd..d79040747ec4dfddc866f0ad36d8423db957e98d 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -42,6 +42,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.24.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/0691-Fix-OfflinePlayer-getBedSpawnLocation.patch b/patches/server/0691-Fix-OfflinePlayer-getBedSpawnLocation.patch new file mode 100644 index 0000000000..4726c2f65c --- /dev/null +++ b/patches/server/0691-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/0692-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch b/patches/server/0692-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch new file mode 100644 index 0000000000..7158b83635 --- /dev/null +++ b/patches/server/0692-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/0692-Fix-OfflinePlayer-getBedSpawnLocation.patch b/patches/server/0692-Fix-OfflinePlayer-getBedSpawnLocation.patch deleted file mode 100644 index 4726c2f65c..0000000000 --- a/patches/server/0692-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/0693-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch b/patches/server/0693-Fix-FurnaceInventory-for-smokers-and-blast-furnaces.patch deleted file mode 100644 index 7158b83635..0000000000 --- a/patches/server/0693-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/0693-Sanitize-sent-BlockEntity-NBT.patch b/patches/server/0693-Sanitize-sent-BlockEntity-NBT.patch new file mode 100644 index 0000000000..6225689cb3 --- /dev/null +++ b/patches/server/0693-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 b1ed43287d522e08a967ba751a851776351916e7..2356fd4bf4edb8a44312f772eeb8399b3a2fa216 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 +@@ -377,6 +377,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/0694-Disable-component-selector-resolving-in-books-by-def.patch b/patches/server/0694-Disable-component-selector-resolving-in-books-by-def.patch new file mode 100644 index 0000000000..7231198032 --- /dev/null +++ b/patches/server/0694-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/0694-Sanitize-sent-BlockEntity-NBT.patch b/patches/server/0694-Sanitize-sent-BlockEntity-NBT.patch deleted file mode 100644 index 6225689cb3..0000000000 --- a/patches/server/0694-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 b1ed43287d522e08a967ba751a851776351916e7..2356fd4bf4edb8a44312f772eeb8399b3a2fa216 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 -@@ -377,6 +377,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/0695-Disable-component-selector-resolving-in-books-by-def.patch b/patches/server/0695-Disable-component-selector-resolving-in-books-by-def.patch deleted file mode 100644 index 7231198032..0000000000 --- a/patches/server/0695-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/0695-Prevent-entity-loading-causing-async-lookups.patch b/patches/server/0695-Prevent-entity-loading-causing-async-lookups.patch new file mode 100644 index 0000000000..aeeb1e6d38 --- /dev/null +++ b/patches/server/0695-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 d078f48a7652a2e01984329ccf8301daa7ec4c38..8a4f99fcc32daad1e20035f9ad61a6d9801d1e3c 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -729,6 +729,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/0696-Prevent-entity-loading-causing-async-lookups.patch b/patches/server/0696-Prevent-entity-loading-causing-async-lookups.patch deleted file mode 100644 index 59efbd6204..0000000000 --- a/patches/server/0696-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 8cf1a2a4dbf1d26d17dc5b4f67a52f7df54dae81..36f82ba16f30fe4054b19e62a8157cf3d4d07671 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -729,6 +729,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/0696-Throw-exception-on-world-create-while-being-ticked.patch b/patches/server/0696-Throw-exception-on-world-create-while-being-ticked.patch new file mode 100644 index 0000000000..b3abc73cb6 --- /dev/null +++ b/patches/server/0696-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 fcc00d5b0be3d2adb92c8243ccca8d0190fcc413..75ca3bc86c9f70df4ddf29a454b8b2bc251b4b9f 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(); +@@ -1626,7 +1627,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/0697-Dont-resent-entity-on-art-update.patch b/patches/server/0697-Dont-resent-entity-on-art-update.patch new file mode 100644 index 0000000000..38d1a4ca58 --- /dev/null +++ b/patches/server/0697-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/0697-Throw-exception-on-world-create-while-being-ticked.patch b/patches/server/0697-Throw-exception-on-world-create-while-being-ticked.patch deleted file mode 100644 index b3abc73cb6..0000000000 --- a/patches/server/0697-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 fcc00d5b0be3d2adb92c8243ccca8d0190fcc413..75ca3bc86c9f70df4ddf29a454b8b2bc251b4b9f 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(); -@@ -1626,7 +1627,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/0698-Add-WardenAngerChangeEvent.patch b/patches/server/0698-Add-WardenAngerChangeEvent.patch new file mode 100644 index 0000000000..8df5686f9f --- /dev/null +++ b/patches/server/0698-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 136e43782c44869df96286c9cd75ed1faa762eec..c47ed605f0822effd58df4f875297ed015e1e57e 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/0698-Dont-resent-entity-on-art-update.patch b/patches/server/0698-Dont-resent-entity-on-art-update.patch deleted file mode 100644 index 38d1a4ca58..0000000000 --- a/patches/server/0698-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/0699-Add-WardenAngerChangeEvent.patch b/patches/server/0699-Add-WardenAngerChangeEvent.patch deleted file mode 100644 index 8df5686f9f..0000000000 --- a/patches/server/0699-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 136e43782c44869df96286c9cd75ed1faa762eec..c47ed605f0822effd58df4f875297ed015e1e57e 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/0699-Add-option-for-strict-advancement-dimension-checks.patch b/patches/server/0699-Add-option-for-strict-advancement-dimension-checks.patch new file mode 100644 index 0000000000..707c7aaf9d --- /dev/null +++ b/patches/server/0699-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 ed8a1457b99f862762e49c84db2585ce410f278a..2821203352974f5bd1e873969f3bc64842761702 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1646,6 +1646,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/0700-Add-missing-important-BlockStateListPopulator-method.patch b/patches/server/0700-Add-missing-important-BlockStateListPopulator-method.patch new file mode 100644 index 0000000000..94a1b50995 --- /dev/null +++ b/patches/server/0700-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 e32321f46625a3f08a9b6adb8f35895d0ee1b14e..514084aff8412251432dfe174a445ddb43361aed 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java +@@ -130,7 +130,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 +@@ -159,4 +159,33 @@ public class BlockStateListPopulator extends DummyGeneratorAccess { + public RandomSource getRandom() { + return this.world.getRandom(); + } ++ ++ // 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/0700-Add-option-for-strict-advancement-dimension-checks.patch b/patches/server/0700-Add-option-for-strict-advancement-dimension-checks.patch deleted file mode 100644 index 97a9fe7a86..0000000000 --- a/patches/server/0700-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 15158bec7e2ca90b45347ba09cf17f25e919f9cf..6236f5cbd32e9547bbb1312c322195e440dadc60 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1646,6 +1646,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/0701-Add-missing-important-BlockStateListPopulator-method.patch b/patches/server/0701-Add-missing-important-BlockStateListPopulator-method.patch deleted file mode 100644 index 94a1b50995..0000000000 --- a/patches/server/0701-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 e32321f46625a3f08a9b6adb8f35895d0ee1b14e..514084aff8412251432dfe174a445ddb43361aed 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java -@@ -130,7 +130,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 -@@ -159,4 +159,33 @@ public class BlockStateListPopulator extends DummyGeneratorAccess { - public RandomSource getRandom() { - return this.world.getRandom(); - } -+ -+ // 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/0701-Nameable-Banner-API.patch b/patches/server/0701-Nameable-Banner-API.patch new file mode 100644 index 0000000000..b481d9a835 --- /dev/null +++ b/patches/server/0701-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 6a2bb16ac915c80316f05348ad15724ddc7e19b4..27fd8b88dc1433c1df1e09604a3cc546bfa0d2b9 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/0702-Don-t-broadcast-messages-to-command-blocks.patch b/patches/server/0702-Don-t-broadcast-messages-to-command-blocks.patch new file mode 100644 index 0000000000..e27e3d40a7 --- /dev/null +++ b/patches/server/0702-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 557eb1a75a3115c3215315deae56a42d665693df..e890f87c66e95e7d4f130c4c659c6662b4f4bd94 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/0702-Nameable-Banner-API.patch b/patches/server/0702-Nameable-Banner-API.patch deleted file mode 100644 index b481d9a835..0000000000 --- a/patches/server/0702-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 6a2bb16ac915c80316f05348ad15724ddc7e19b4..27fd8b88dc1433c1df1e09604a3cc546bfa0d2b9 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/0703-Don-t-broadcast-messages-to-command-blocks.patch b/patches/server/0703-Don-t-broadcast-messages-to-command-blocks.patch deleted file mode 100644 index e27e3d40a7..0000000000 --- a/patches/server/0703-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 557eb1a75a3115c3215315deae56a42d665693df..e890f87c66e95e7d4f130c4c659c6662b4f4bd94 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/0703-Prevent-empty-items-from-being-added-to-world.patch b/patches/server/0703-Prevent-empty-items-from-being-added-to-world.patch new file mode 100644 index 0000000000..77b154f4ed --- /dev/null +++ b/patches/server/0703-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 ee0459e37b817648e37b1ea84a3edf7c52d00855..528c2a0aff23255275982ce3e42ce16087992f57 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1206,6 +1206,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/0704-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch b/patches/server/0704-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch new file mode 100644 index 0000000000..c2e21a749e --- /dev/null +++ b/patches/server/0704-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/0704-Prevent-empty-items-from-being-added-to-world.patch b/patches/server/0704-Prevent-empty-items-from-being-added-to-world.patch deleted file mode 100644 index 0ce15dc3d4..0000000000 --- a/patches/server/0704-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 08b819c19eda2ab53b1b37af7a90e38b06b67b85..32d368a18e14f247b4ddcb9d3dc16aa116359be4 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1206,6 +1206,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/0705-Add-Player-getFishHook.patch b/patches/server/0705-Add-Player-getFishHook.patch new file mode 100644 index 0000000000..15a4d9dca1 --- /dev/null +++ b/patches/server/0705-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 d5c4184e0d93eabc699661829ff4bf9b46d27142..aa3a47149fec342096817c7b9ce45ea196fd33d0 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/0705-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch b/patches/server/0705-Fix-CCE-for-SplashPotion-and-LingeringPotion-spawnin.patch deleted file mode 100644 index c2e21a749e..0000000000 --- a/patches/server/0705-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/0706-Add-Player-getFishHook.patch b/patches/server/0706-Add-Player-getFishHook.patch deleted file mode 100644 index 15a4d9dca1..0000000000 --- a/patches/server/0706-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 d5c4184e0d93eabc699661829ff4bf9b46d27142..aa3a47149fec342096817c7b9ce45ea196fd33d0 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/0706-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch b/patches/server/0706-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch new file mode 100644 index 0000000000..32aaf6dc6e --- /dev/null +++ b/patches/server/0706-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/0707-Add-various-missing-EntityDropItemEvent-calls.patch b/patches/server/0707-Add-various-missing-EntityDropItemEvent-calls.patch new file mode 100644 index 0000000000..f0dd9ffa73 --- /dev/null +++ b/patches/server/0707-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 8a4f99fcc32daad1e20035f9ad61a6d9801d1e3c..41026637304430f1cbf4ed5dc1d44b807afa90af 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2698,6 +2698,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 273ca38677223c28025629144c39e9e415145f70..7d9d4df95b5abbe340f813a9cb765e59e2bd6fae 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/0707-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch b/patches/server/0707-Do-not-sync-load-chunk-for-dynamic-game-event-listen.patch deleted file mode 100644 index 32aaf6dc6e..0000000000 --- a/patches/server/0707-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/0708-Add-various-missing-EntityDropItemEvent-calls.patch b/patches/server/0708-Add-various-missing-EntityDropItemEvent-calls.patch deleted file mode 100644 index 91e73baabd..0000000000 --- a/patches/server/0708-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 36f82ba16f30fe4054b19e62a8157cf3d4d07671..ad548e41740221fa5bb1aee6ba484e213bd1e779 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2698,6 +2698,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 273ca38677223c28025629144c39e9e415145f70..7d9d4df95b5abbe340f813a9cb765e59e2bd6fae 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/0708-Fix-Bee-flower-NPE.patch b/patches/server/0708-Fix-Bee-flower-NPE.patch new file mode 100644 index 0000000000..17dc8e7e29 --- /dev/null +++ b/patches/server/0708-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 a5eab5cdb761e3e9d37ea66287f26a2c3345182d..ca706f1ac5f4248164daa613eef81e46b3e5a210 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java +@@ -974,7 +974,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/0709-Fix-Bee-flower-NPE.patch b/patches/server/0709-Fix-Bee-flower-NPE.patch deleted file mode 100644 index 17dc8e7e29..0000000000 --- a/patches/server/0709-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 a5eab5cdb761e3e9d37ea66287f26a2c3345182d..ca706f1ac5f4248164daa613eef81e46b3e5a210 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -974,7 +974,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/0709-More-Teleport-API.patch b/patches/server/0709-More-Teleport-API.patch new file mode 100644 index 0000000000..8aa4c173f9 --- /dev/null +++ b/patches/server/0709-More-Teleport-API.patch @@ -0,0 +1,265 @@ +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 864ab4d3de50ee9ce9ff2b0538aa46df43985a84..90eedcb1013226cd4dbbbaf4ff9332a89e6d7c96 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1639,11 +1639,18 @@ 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 ++ final Set relativeFlags = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class); ++ for (final Relative relativeArgument : set) { ++ final io.papermc.paper.entity.TeleportFlag.Relative flag = org.bukkit.craftbukkit.entity.CraftPlayer.deltaRelativeToAPI(relativeArgument); ++ if (flag != null) relativeFlags.add(flag); ++ } ++ 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 10fb64df10820974d11f142c102a11a5bd0f317c..ea62e2725152008e87961cedd837fa0d03787d03 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())) { +@@ -971,6 +992,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.MinecraftServer.getServer().scheduleOnMain(() -> { ++ final net.minecraft.server.level.ServerChunkCache chunkCache = world.getChunkSource(); ++ for (final net.minecraft.world.level.chunk.ChunkAccess chunk : list) { ++ chunkCache.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId()); ++ } ++ 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 eb48efa038043dacf539811de9e0f0faa1ec6b42..f9ab43049c7885d6d51a69abb08e961270de17e9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1293,13 +1293,94 @@ 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 ++ if (this.getHandle().connection == null) return; ++ this.getHandle().forceSetRotation(yaw, pitch); ++ // Paper end - Teleportation API + } + + @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 deltaRelativeToNMS(io.papermc.paper.entity.TeleportFlag.Relative apiFlag) { ++ return switch (apiFlag) { ++ case VELOCITY_X -> net.minecraft.world.entity.Relative.DELTA_X; ++ case VELOCITY_Y -> net.minecraft.world.entity.Relative.DELTA_Y; ++ case VELOCITY_Z -> net.minecraft.world.entity.Relative.DELTA_Z; ++ case VELOCITY_ROTATION -> net.minecraft.world.entity.Relative.ROTATE_DELTA; ++ }; ++ } ++ ++ public static @org.jetbrains.annotations.Nullable io.papermc.paper.entity.TeleportFlag.Relative deltaRelativeToAPI(net.minecraft.world.entity.Relative nmsFlag) { ++ return switch (nmsFlag) { ++ case DELTA_X -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_X; ++ case DELTA_Y -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_Y; ++ case DELTA_Z -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_Z; ++ case ROTATE_DELTA -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_ROTATION; ++ default -> null; ++ }; ++ } ++ ++ @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(); +@@ -1312,7 +1393,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + return false; + } + +- if (entity.isVehicle()) { ++ if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API + return false; + } + +@@ -1321,7 +1402,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. +@@ -1330,7 +1411,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()) { +@@ -1346,13 +1427,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(deltaRelativeToNMS(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/0710-Add-EntityPortalReadyEvent.patch b/patches/server/0710-Add-EntityPortalReadyEvent.patch new file mode 100644 index 0000000000..086f824533 --- /dev/null +++ b/patches/server/0710-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 151025a407a07271bc205955f0ce06f84231563b..ac894e5651ea6145727639e2882edb236a47fb02 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/0710-More-Teleport-API.patch b/patches/server/0710-More-Teleport-API.patch deleted file mode 100644 index 8aa4c173f9..0000000000 --- a/patches/server/0710-More-Teleport-API.patch +++ /dev/null @@ -1,265 +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 864ab4d3de50ee9ce9ff2b0538aa46df43985a84..90eedcb1013226cd4dbbbaf4ff9332a89e6d7c96 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1639,11 +1639,18 @@ 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 -+ final Set relativeFlags = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class); -+ for (final Relative relativeArgument : set) { -+ final io.papermc.paper.entity.TeleportFlag.Relative flag = org.bukkit.craftbukkit.entity.CraftPlayer.deltaRelativeToAPI(relativeArgument); -+ if (flag != null) relativeFlags.add(flag); -+ } -+ 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 10fb64df10820974d11f142c102a11a5bd0f317c..ea62e2725152008e87961cedd837fa0d03787d03 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())) { -@@ -971,6 +992,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.MinecraftServer.getServer().scheduleOnMain(() -> { -+ final net.minecraft.server.level.ServerChunkCache chunkCache = world.getChunkSource(); -+ for (final net.minecraft.world.level.chunk.ChunkAccess chunk : list) { -+ chunkCache.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId()); -+ } -+ 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 eb48efa038043dacf539811de9e0f0faa1ec6b42..f9ab43049c7885d6d51a69abb08e961270de17e9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1293,13 +1293,94 @@ 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 -+ if (this.getHandle().connection == null) return; -+ this.getHandle().forceSetRotation(yaw, pitch); -+ // Paper end - Teleportation API - } - - @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 deltaRelativeToNMS(io.papermc.paper.entity.TeleportFlag.Relative apiFlag) { -+ return switch (apiFlag) { -+ case VELOCITY_X -> net.minecraft.world.entity.Relative.DELTA_X; -+ case VELOCITY_Y -> net.minecraft.world.entity.Relative.DELTA_Y; -+ case VELOCITY_Z -> net.minecraft.world.entity.Relative.DELTA_Z; -+ case VELOCITY_ROTATION -> net.minecraft.world.entity.Relative.ROTATE_DELTA; -+ }; -+ } -+ -+ public static @org.jetbrains.annotations.Nullable io.papermc.paper.entity.TeleportFlag.Relative deltaRelativeToAPI(net.minecraft.world.entity.Relative nmsFlag) { -+ return switch (nmsFlag) { -+ case DELTA_X -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_X; -+ case DELTA_Y -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_Y; -+ case DELTA_Z -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_Z; -+ case ROTATE_DELTA -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_ROTATION; -+ default -> null; -+ }; -+ } -+ -+ @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(); -@@ -1312,7 +1393,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - return false; - } - -- if (entity.isVehicle()) { -+ if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API - return false; - } - -@@ -1321,7 +1402,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. -@@ -1330,7 +1411,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()) { -@@ -1346,13 +1427,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(deltaRelativeToNMS(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/0711-Add-EntityPortalReadyEvent.patch b/patches/server/0711-Add-EntityPortalReadyEvent.patch deleted file mode 100644 index 086f824533..0000000000 --- a/patches/server/0711-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 151025a407a07271bc205955f0ce06f84231563b..ac894e5651ea6145727639e2882edb236a47fb02 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/0711-Don-t-use-level-random-in-entity-constructors.patch b/patches/server/0711-Don-t-use-level-random-in-entity-constructors.patch new file mode 100644 index 0000000000..d083d9ffea --- /dev/null +++ b/patches/server/0711-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 586257fe5c9f5cddd0ed164254f46777c6e71d66..d555fd0b200c012f30ed0c0ec09a37b25a737b76 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 1d5de664af21013f68d59b326b1427bc632352de..809f5e847e2f5bb594c130cebd2cb897ea768d82 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/0712-Don-t-use-level-random-in-entity-constructors.patch b/patches/server/0712-Don-t-use-level-random-in-entity-constructors.patch deleted file mode 100644 index d083d9ffea..0000000000 --- a/patches/server/0712-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 586257fe5c9f5cddd0ed164254f46777c6e71d66..d555fd0b200c012f30ed0c0ec09a37b25a737b76 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 1d5de664af21013f68d59b326b1427bc632352de..809f5e847e2f5bb594c130cebd2cb897ea768d82 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/0712-Send-block-entities-after-destroy-prediction.patch b/patches/server/0712-Send-block-entities-after-destroy-prediction.patch new file mode 100644 index 0000000000..f82930ea8f --- /dev/null +++ b/patches/server/0712-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 90eedcb1013226cd4dbbbaf4ff9332a89e6d7c96..aeaf2d4f7a0ad0621c210cd479c610104ec7a83b 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1779,8 +1779,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/0713-Send-block-entities-after-destroy-prediction.patch b/patches/server/0713-Send-block-entities-after-destroy-prediction.patch deleted file mode 100644 index f82930ea8f..0000000000 --- a/patches/server/0713-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 90eedcb1013226cd4dbbbaf4ff9332a89e6d7c96..aeaf2d4f7a0ad0621c210cd479c610104ec7a83b 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1779,8 +1779,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/0713-Warn-on-plugins-accessing-faraway-chunks.patch b/patches/server/0713-Warn-on-plugins-accessing-faraway-chunks.patch new file mode 100644 index 0000000000..056fcc0002 --- /dev/null +++ b/patches/server/0713-Warn-on-plugins-accessing-faraway-chunks.patch @@ -0,0 +1,105 @@ +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 a1731f09e724794be90dbf47e1d463a10cdb3052..447e4c77b5cd90e744e014b66af5f0a9ebe9c2d8 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -338,7 +338,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 827cf8b2e241e49dac961b103f32546a04f8a2f9..5379931b2403566f54e4ecf0699229d636d2d38f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -302,9 +302,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 + net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) this.world.getChunk(x, z, ChunkStatus.FULL, true); + return new CraftChunk(chunk); + } +@@ -400,6 +415,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); +@@ -473,6 +489,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. +@@ -505,6 +522,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"); + +@@ -605,6 +623,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); + } + +@@ -939,6 +958,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); + } +@@ -2344,6 +2364,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + // Paper start + @Override + public void getChunkAtAsync(int x, int z, boolean gen, boolean urgent, @NotNull Consumer cb) { ++ warnUnsafeChunk("getting a faraway chunk async", x, z); // Paper + ca.spottedleaf.moonrise.common.util.ChunkSystem.scheduleChunkLoad( + this.getHandle(), x, z, gen, ChunkStatus.FULL, true, + urgent ? ca.spottedleaf.concurrentutil.util.Priority.HIGHER : ca.spottedleaf.concurrentutil.util.Priority.NORMAL, +@@ -2356,6 +2377,8 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void getChunksAtAsync(int minX, int minZ, int maxX, int maxZ, boolean urgent, Runnable cb) { ++ warnUnsafeChunk("getting a faraway chunk async", minX, minZ); // Paper ++ warnUnsafeChunk("getting a faraway chunk async", maxX, maxZ); // Paper + this.getHandle().loadChunks( + minX, minZ, maxX, maxZ, + urgent ? ca.spottedleaf.concurrentutil.util.Priority.HIGHER : ca.spottedleaf.concurrentutil.util.Priority.NORMAL, diff --git a/patches/server/0714-Custom-Chat-Completion-Suggestions-API.patch b/patches/server/0714-Custom-Chat-Completion-Suggestions-API.patch new file mode 100644 index 0000000000..3ec8f74557 --- /dev/null +++ b/patches/server/0714-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 f9ab43049c7885d6d51a69abb08e961270de17e9..0bbd2c533f2c6f42464c058b1eea86d210cbdf93 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -698,6 +698,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/0714-Warn-on-plugins-accessing-faraway-chunks.patch b/patches/server/0714-Warn-on-plugins-accessing-faraway-chunks.patch deleted file mode 100644 index 056fcc0002..0000000000 --- a/patches/server/0714-Warn-on-plugins-accessing-faraway-chunks.patch +++ /dev/null @@ -1,105 +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 a1731f09e724794be90dbf47e1d463a10cdb3052..447e4c77b5cd90e744e014b66af5f0a9ebe9c2d8 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -338,7 +338,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 827cf8b2e241e49dac961b103f32546a04f8a2f9..5379931b2403566f54e4ecf0699229d636d2d38f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -302,9 +302,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 - net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) this.world.getChunk(x, z, ChunkStatus.FULL, true); - return new CraftChunk(chunk); - } -@@ -400,6 +415,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); -@@ -473,6 +489,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. -@@ -505,6 +522,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"); - -@@ -605,6 +623,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); - } - -@@ -939,6 +958,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); - } -@@ -2344,6 +2364,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - // Paper start - @Override - public void getChunkAtAsync(int x, int z, boolean gen, boolean urgent, @NotNull Consumer cb) { -+ warnUnsafeChunk("getting a faraway chunk async", x, z); // Paper - ca.spottedleaf.moonrise.common.util.ChunkSystem.scheduleChunkLoad( - this.getHandle(), x, z, gen, ChunkStatus.FULL, true, - urgent ? ca.spottedleaf.concurrentutil.util.Priority.HIGHER : ca.spottedleaf.concurrentutil.util.Priority.NORMAL, -@@ -2356,6 +2377,8 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void getChunksAtAsync(int minX, int minZ, int maxX, int maxZ, boolean urgent, Runnable cb) { -+ warnUnsafeChunk("getting a faraway chunk async", minX, minZ); // Paper -+ warnUnsafeChunk("getting a faraway chunk async", maxX, maxZ); // Paper - this.getHandle().loadChunks( - minX, minZ, maxX, maxZ, - urgent ? ca.spottedleaf.concurrentutil.util.Priority.HIGHER : ca.spottedleaf.concurrentutil.util.Priority.NORMAL, diff --git a/patches/server/0715-Add-and-fix-missing-BlockFadeEvents.patch b/patches/server/0715-Add-and-fix-missing-BlockFadeEvents.patch new file mode 100644 index 0000000000..1ac5d1e5ab --- /dev/null +++ b/patches/server/0715-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/0715-Custom-Chat-Completion-Suggestions-API.patch b/patches/server/0715-Custom-Chat-Completion-Suggestions-API.patch deleted file mode 100644 index 3ec8f74557..0000000000 --- a/patches/server/0715-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 f9ab43049c7885d6d51a69abb08e961270de17e9..0bbd2c533f2c6f42464c058b1eea86d210cbdf93 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -698,6 +698,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/0716-Add-and-fix-missing-BlockFadeEvents.patch b/patches/server/0716-Add-and-fix-missing-BlockFadeEvents.patch deleted file mode 100644 index 1ac5d1e5ab..0000000000 --- a/patches/server/0716-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/0716-Collision-API.patch b/patches/server/0716-Collision-API.patch new file mode 100644 index 0000000000..04a7bbffba --- /dev/null +++ b/patches/server/0716-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 ea62e2725152008e87961cedd837fa0d03787d03..1edccd83ecc498ebc07c3c6ca019eeb28c897973 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1189,4 +1189,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/0717-Collision-API.patch b/patches/server/0717-Collision-API.patch deleted file mode 100644 index 04a7bbffba..0000000000 --- a/patches/server/0717-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 ea62e2725152008e87961cedd837fa0d03787d03..1edccd83ecc498ebc07c3c6ca019eeb28c897973 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1189,4 +1189,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/0717-Fix-suggest-command-message-for-brigadier-syntax-exc.patch b/patches/server/0717-Fix-suggest-command-message-for-brigadier-syntax-exc.patch new file mode 100644 index 0000000000..4627673f0f --- /dev/null +++ b/patches/server/0717-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 800d1756db8c27b7d129a90addc125c4fc81e134..977f9ac300490562d9894af4a42621b594f0a8e0 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/0718-Block-Ticking-API.patch b/patches/server/0718-Block-Ticking-API.patch new file mode 100644 index 0000000000..f143dbcf0e --- /dev/null +++ b/patches/server/0718-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 78071859e9b745b2497fec7761888b4e65a208a1..fd941d9e38fa6c886b6779eaa63eebe00e1fa1b5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +@@ -761,4 +761,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/0718-Fix-suggest-command-message-for-brigadier-syntax-exc.patch b/patches/server/0718-Fix-suggest-command-message-for-brigadier-syntax-exc.patch deleted file mode 100644 index 4627673f0f..0000000000 --- a/patches/server/0718-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 800d1756db8c27b7d129a90addc125c4fc81e134..977f9ac300490562d9894af4a42621b594f0a8e0 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/0719-Add-Velocity-IP-Forwarding-Support.patch b/patches/server/0719-Add-Velocity-IP-Forwarding-Support.patch new file mode 100644 index 0000000000..a276b2c88d --- /dev/null +++ b/patches/server/0719-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 e890f87c66e95e7d4f130c4c659c6662b4f4bd94..927846bf3281771de0274216abe927e524df3493 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/0719-Block-Ticking-API.patch b/patches/server/0719-Block-Ticking-API.patch deleted file mode 100644 index f143dbcf0e..0000000000 --- a/patches/server/0719-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 78071859e9b745b2497fec7761888b4e65a208a1..fd941d9e38fa6c886b6779eaa63eebe00e1fa1b5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -@@ -761,4 +761,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/0720-Add-NamespacedKey-biome-methods.patch b/patches/server/0720-Add-NamespacedKey-biome-methods.patch new file mode 100644 index 0000000000..8420d9c080 --- /dev/null +++ b/patches/server/0720-Add-NamespacedKey-biome-methods.patch @@ -0,0 +1,28 @@ +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 d7698f8ae59195458148397406a104224676b76e..088ff124ca82e69e59e02e6604959e399e4aff03 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -598,6 +598,16 @@ 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) { ++ return accessor.getBiome(x, y, z).getKey(); ++ } ++ ++ @Override ++ public void setBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z, org.bukkit.NamespacedKey biomeKey) { ++ accessor.setBiome(x, y, z, org.bukkit.Registry.BIOME.getOrThrow(biomeKey)); ++ } + // Paper end + + /** diff --git a/patches/server/0720-Add-Velocity-IP-Forwarding-Support.patch b/patches/server/0720-Add-Velocity-IP-Forwarding-Support.patch deleted file mode 100644 index a276b2c88d..0000000000 --- a/patches/server/0720-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 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 e890f87c66e95e7d4f130c4c659c6662b4f4bd94..927846bf3281771de0274216abe927e524df3493 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/0721-Add-NamespacedKey-biome-methods.patch b/patches/server/0721-Add-NamespacedKey-biome-methods.patch deleted file mode 100644 index 8420d9c080..0000000000 --- a/patches/server/0721-Add-NamespacedKey-biome-methods.patch +++ /dev/null @@ -1,28 +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 d7698f8ae59195458148397406a104224676b76e..088ff124ca82e69e59e02e6604959e399e4aff03 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -598,6 +598,16 @@ 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) { -+ return accessor.getBiome(x, y, z).getKey(); -+ } -+ -+ @Override -+ public void setBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z, org.bukkit.NamespacedKey biomeKey) { -+ accessor.setBiome(x, y, z, org.bukkit.Registry.BIOME.getOrThrow(biomeKey)); -+ } - // Paper end - - /** diff --git a/patches/server/0721-Fix-plugin-loggers-on-server-shutdown.patch b/patches/server/0721-Fix-plugin-loggers-on-server-shutdown.patch new file mode 100644 index 0000000000..d88c01161e --- /dev/null +++ b/patches/server/0721-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 75ca3bc86c9f70df4ddf29a454b8b2bc251b4b9f..b88a91ff85727109241991f76ebad7c0119ad436 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1276,6 +1276,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 75ca3bc86c9f70df4ddf29a454b8b2bc251b4b9f..b88a91ff85727109241991f76ebad7c0119ad436 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1276,6 +1276,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 91fc54b060d8ab5d8e60a09677afbe1b46798064..28eb50111e524bce5aadb1dd2eea14a7df0105f2 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3282,37 +3282,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 f3781e37358f970b56e5b8de77ef224151270f1c..92bf8a3bac1146ed2393faa0f31e219288b466ca 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +@@ -413,13 +413,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/0723-Fire-EntityChangeBlockEvent-in-more-places.patch b/patches/server/0723-Fire-EntityChangeBlockEvent-in-more-places.patch new file mode 100644 index 0000000000..49bb57e2aa --- /dev/null +++ b/patches/server/0723-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 069535725720520b93dffd44ba1bc434528fd995..b4937f04b4cae1ddff8d6df0f608b2f2e3fb367c 100644 +--- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java +@@ -245,6 +245,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())); +@@ -275,11 +280,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); +@@ -320,11 +330,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); +@@ -335,6 +347,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 801528022c902714138c264bc4d05ef0df85912e..039e42aa243136234009217a5232900d31037de6 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 +@@ -255,7 +255,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/0723-Stop-large-look-changes-from-crashing-the-server.patch b/patches/server/0723-Stop-large-look-changes-from-crashing-the-server.patch deleted file mode 100644 index 9bf6f902e6..0000000000 --- a/patches/server/0723-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 91fc54b060d8ab5d8e60a09677afbe1b46798064..28eb50111e524bce5aadb1dd2eea14a7df0105f2 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3282,37 +3282,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 f3781e37358f970b56e5b8de77ef224151270f1c..92bf8a3bac1146ed2393faa0f31e219288b466ca 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -413,13 +413,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/0724-Fire-EntityChangeBlockEvent-in-more-places.patch b/patches/server/0724-Fire-EntityChangeBlockEvent-in-more-places.patch deleted file mode 100644 index 49bb57e2aa..0000000000 --- a/patches/server/0724-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 069535725720520b93dffd44ba1bc434528fd995..b4937f04b4cae1ddff8d6df0f608b2f2e3fb367c 100644 ---- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -@@ -245,6 +245,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())); -@@ -275,11 +280,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); -@@ -320,11 +330,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); -@@ -335,6 +347,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 801528022c902714138c264bc4d05ef0df85912e..039e42aa243136234009217a5232900d31037de6 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 -@@ -255,7 +255,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/0724-Missing-eating-regain-reason.patch b/patches/server/0724-Missing-eating-regain-reason.patch new file mode 100644 index 0000000000..9b79d094d3 --- /dev/null +++ b/patches/server/0724-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 9a67dfe214d3eb89d1f4371e716df759651ceb1b..989b7be74eaeba7f40eac87c7ee7f252cb0c05c9 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java +@@ -406,7 +406,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/0725-Missing-eating-regain-reason.patch b/patches/server/0725-Missing-eating-regain-reason.patch deleted file mode 100644 index 9b79d094d3..0000000000 --- a/patches/server/0725-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 9a67dfe214d3eb89d1f4371e716df759651ceb1b..989b7be74eaeba7f40eac87c7ee7f252cb0c05c9 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -406,7 +406,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/0725-Missing-effect-cause.patch b/patches/server/0725-Missing-effect-cause.patch new file mode 100644 index 0000000000..85e40f7bb1 --- /dev/null +++ b/patches/server/0725-Missing-effect-cause.patch @@ -0,0 +1,32 @@ +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/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java +index ca706f1ac5f4248164daa613eef81e46b3e5a210..0bafe14342c1acce131ad34717c18aed3718deed 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java +@@ -636,7 +636,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + if (mobeffect != null) { + this.usePlayerItem(player, hand, itemstack); + if (!this.level().isClientSide) { +- this.addEffect(mobeffect); ++ this.addEffect(mobeffect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD); // Paper - Add missing effect cause + } + + return InteractionResult.SUCCESS; +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/0726-Added-byte-array-serialization-deserialization-for-P.patch b/patches/server/0726-Added-byte-array-serialization-deserialization-for-P.patch new file mode 100644 index 0000000000..f2a4d437f0 --- /dev/null +++ b/patches/server/0726-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/0726-Missing-effect-cause.patch b/patches/server/0726-Missing-effect-cause.patch deleted file mode 100644 index 85e40f7bb1..0000000000 --- a/patches/server/0726-Missing-effect-cause.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: Tue, 16 Aug 2022 19:44:55 +0200 -Subject: [PATCH] Missing effect cause - - -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 ca706f1ac5f4248164daa613eef81e46b3e5a210..0bafe14342c1acce131ad34717c18aed3718deed 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -636,7 +636,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - if (mobeffect != null) { - this.usePlayerItem(player, hand, itemstack); - if (!this.level().isClientSide) { -- this.addEffect(mobeffect); -+ this.addEffect(mobeffect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD); // Paper - Add missing effect cause - } - - return InteractionResult.SUCCESS; -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/0727-Add-source-block-to-BlockPhysicsEvent.patch b/patches/server/0727-Add-source-block-to-BlockPhysicsEvent.patch new file mode 100644 index 0000000000..91adea4a23 --- /dev/null +++ b/patches/server/0727-Add-source-block-to-BlockPhysicsEvent.patch @@ -0,0 +1,42 @@ +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] Add source block to BlockPhysicsEvent + + +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..3a95e3236eafd14baed035e53503b58c2e21b68a 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,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater { + orientation = this.orientation.withFront(direction); + } + +- NeighborUpdater.executeUpdate(world, blockState, blockPos, this.sourceBlock, orientation, false); ++ NeighborUpdater.executeUpdate(world, blockState, blockPos, this.sourceBlock, orientation, false, this.sourcePos); // Paper - Add source block to BlockPhysicsEvent + if (this.idx < NeighborUpdater.UPDATE_ORDER.length && NeighborUpdater.UPDATE_ORDER[this.idx] == this.skipDirection) { + this.idx++; + } +diff --git a/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java +index be8f34dd222e43b2db7f05e5e5839df8446e1b02..e414da8a51bb9b49c28a74eca166046cbee44835 100644 +--- a/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java ++++ b/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java +@@ -55,11 +55,17 @@ public interface NeighborUpdater { + } + + static void executeUpdate(Level world, BlockState state, BlockPos pos, Block sourceBlock, @Nullable Orientation orientation, boolean notify) { ++ // Paper start - Add source block to BlockPhysicsEvent ++ executeUpdate(world, state, pos, sourceBlock, orientation, notify, pos); ++ } ++ ++ static void executeUpdate(Level world, BlockState state, BlockPos pos, Block sourceBlock, @Nullable Orientation orientation, boolean notify, BlockPos sourcePos) { ++ // Paper end - Add source block to BlockPhysicsEvent + try { + // CraftBukkit start + CraftWorld cworld = ((ServerLevel) world).getWorld(); + if (cworld != null) { +- BlockPhysicsEvent event = new BlockPhysicsEvent(CraftBlock.at(world, pos), CraftBlockData.fromData(state)); ++ BlockPhysicsEvent event = new BlockPhysicsEvent(CraftBlock.at(world, pos), CraftBlockData.fromData(state), CraftBlock.at(world, sourcePos)); // Paper - Add source block to BlockPhysicsEvent + ((ServerLevel) world).getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { diff --git a/patches/server/0727-Added-byte-array-serialization-deserialization-for-P.patch b/patches/server/0727-Added-byte-array-serialization-deserialization-for-P.patch deleted file mode 100644 index f2a4d437f0..0000000000 --- a/patches/server/0727-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/0728-Add-source-block-to-BlockPhysicsEvent.patch b/patches/server/0728-Add-source-block-to-BlockPhysicsEvent.patch deleted file mode 100644 index 91adea4a23..0000000000 --- a/patches/server/0728-Add-source-block-to-BlockPhysicsEvent.patch +++ /dev/null @@ -1,42 +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] Add source block to BlockPhysicsEvent - - -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..3a95e3236eafd14baed035e53503b58c2e21b68a 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,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater { - orientation = this.orientation.withFront(direction); - } - -- NeighborUpdater.executeUpdate(world, blockState, blockPos, this.sourceBlock, orientation, false); -+ NeighborUpdater.executeUpdate(world, blockState, blockPos, this.sourceBlock, orientation, false, this.sourcePos); // Paper - Add source block to BlockPhysicsEvent - if (this.idx < NeighborUpdater.UPDATE_ORDER.length && NeighborUpdater.UPDATE_ORDER[this.idx] == this.skipDirection) { - this.idx++; - } -diff --git a/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java -index be8f34dd222e43b2db7f05e5e5839df8446e1b02..e414da8a51bb9b49c28a74eca166046cbee44835 100644 ---- a/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java -+++ b/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java -@@ -55,11 +55,17 @@ public interface NeighborUpdater { - } - - static void executeUpdate(Level world, BlockState state, BlockPos pos, Block sourceBlock, @Nullable Orientation orientation, boolean notify) { -+ // Paper start - Add source block to BlockPhysicsEvent -+ executeUpdate(world, state, pos, sourceBlock, orientation, notify, pos); -+ } -+ -+ static void executeUpdate(Level world, BlockState state, BlockPos pos, Block sourceBlock, @Nullable Orientation orientation, boolean notify, BlockPos sourcePos) { -+ // Paper end - Add source block to BlockPhysicsEvent - try { - // CraftBukkit start - CraftWorld cworld = ((ServerLevel) world).getWorld(); - if (cworld != null) { -- BlockPhysicsEvent event = new BlockPhysicsEvent(CraftBlock.at(world, pos), CraftBlockData.fromData(state)); -+ BlockPhysicsEvent event = new BlockPhysicsEvent(CraftBlock.at(world, pos), CraftBlockData.fromData(state), CraftBlock.at(world, sourcePos)); // Paper - Add source block to BlockPhysicsEvent - ((ServerLevel) world).getCraftServer().getPluginManager().callEvent(event); - - if (event.isCancelled()) { diff --git a/patches/server/0728-Configurable-chat-thread-limit.patch b/patches/server/0728-Configurable-chat-thread-limit.patch new file mode 100644 index 0000000000..43277b9fb4 --- /dev/null +++ b/patches/server/0728-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 2eb155d3df2e34c050fd28c5a64015e6e1232851..d8db428f06606c16466d39cceb2a5e02eb3d3b24 100644 +--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java ++++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +@@ -300,7 +300,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/0729-Configurable-chat-thread-limit.patch b/patches/server/0729-Configurable-chat-thread-limit.patch deleted file mode 100644 index 43277b9fb4..0000000000 --- a/patches/server/0729-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 2eb155d3df2e34c050fd28c5a64015e6e1232851..d8db428f06606c16466d39cceb2a5e02eb3d3b24 100644 ---- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -300,7 +300,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/0729-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch b/patches/server/0729-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch new file mode 100644 index 0000000000..3ce15af172 --- /dev/null +++ b/patches/server/0729-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 5a7aa491e0846ca8133bc4bb6e74b93cff85fb17..2a2e37a7c67cac657712fc20746a892097a3c4be 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +@@ -463,6 +463,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/0730-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch b/patches/server/0730-Mitigate-effects-of-WorldCreator-keepSpawnLoaded-ret.patch deleted file mode 100644 index 3ce15af172..0000000000 --- a/patches/server/0730-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 5a7aa491e0846ca8133bc4bb6e74b93cff85fb17..2a2e37a7c67cac657712fc20746a892097a3c4be 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java -@@ -463,6 +463,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/0730-fix-Jigsaw-block-kicking-user.patch b/patches/server/0730-fix-Jigsaw-block-kicking-user.patch new file mode 100644 index 0000000000..749d498f57 --- /dev/null +++ b/patches/server/0730-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/0731-fix-Jigsaw-block-kicking-user.patch b/patches/server/0731-fix-Jigsaw-block-kicking-user.patch deleted file mode 100644 index 749d498f57..0000000000 --- a/patches/server/0731-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/0731-use-BlockFormEvent-for-mud-converting-into-clay.patch b/patches/server/0731-use-BlockFormEvent-for-mud-converting-into-clay.patch new file mode 100644 index 0000000000..3159c4b594 --- /dev/null +++ b/patches/server/0731-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/0732-Add-getDrops-to-BlockState.patch b/patches/server/0732-Add-getDrops-to-BlockState.patch new file mode 100644 index 0000000000..ea12f69bde --- /dev/null +++ b/patches/server/0732-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/0732-use-BlockFormEvent-for-mud-converting-into-clay.patch b/patches/server/0732-use-BlockFormEvent-for-mud-converting-into-clay.patch deleted file mode 100644 index 3159c4b594..0000000000 --- a/patches/server/0732-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/0733-Add-getDrops-to-BlockState.patch b/patches/server/0733-Add-getDrops-to-BlockState.patch deleted file mode 100644 index ea12f69bde..0000000000 --- a/patches/server/0733-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/0733-Fix-a-bunch-of-vanilla-bugs.patch b/patches/server/0733-Fix-a-bunch-of-vanilla-bugs.patch new file mode 100644 index 0000000000..1cd84fb056 --- /dev/null +++ b/patches/server/0733-Fix-a-bunch-of-vanilla-bugs.patch @@ -0,0 +1,385 @@ +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-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 +public net/minecraft/server/level/ChunkMap anyPlayerCloseEnoughForSpawning(Lnet/minecraft/world/level/ChunkPos;)Z + +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/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 528c2a0aff23255275982ce3e42ce16087992f57..d778f3dbe84b57f42703042ddd161e5c4bd4f14d 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -754,7 +754,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 aeaf2d4f7a0ad0621c210cd479c610104ec7a83b..c078b3bc75e52456f458c7febc51ea6f8b29f737 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1889,7 +1889,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 91a3b9866e02414d2d71aa53ef1fb5fdecd8cd89..23929b165ff4ca153617c54d022ae43ef5fa258c 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 916017571ecde95721df9bdc07c5e7b5dc60c957..3ef9be2b076160783adce2f1d74b3118544e66da 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, this.getDirection() == 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 c257660c79516a5919032b771fc3ac9575e9db9d..5d7f4e4f420c7e0a3467b7ec3859cae2eb63870f 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 7b63e2fd004ae452c7350f0b2d8d7c57a42891ea..5b2c7b8fb780e837d9d735ac86dcac949732ec69 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 +@@ -526,13 +526,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/TrialSpawner.java b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java +index 476caf7fb4f0124daa35822f2161e11620f18621..b6f9aca593a66fd1e18ab2c4d1989c08824fa6b4 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java +@@ -391,7 +391,7 @@ public final class TrialSpawner { + } + + public void overrideEntityToSpawn(EntityType entityType, Level world) { +- this.data.reset(); ++ this.data.reset(this); // Paper + this.normalConfig = Holder.direct(((TrialSpawnerConfig) this.normalConfig.value()).withSpawning(entityType)); + this.ominousConfig = Holder.direct(((TrialSpawnerConfig) this.ominousConfig.value()).withSpawning(entityType)); + this.setState(world, TrialSpawnerState.INACTIVE); +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 2f808e5f3a5fb2b63f273f6da47292cfd9719bcc..f4ba1afe2f4dc528fc154258d8bc9e144794980f 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 +@@ -100,9 +100,9 @@ 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(); ++ if (!logic.getConfig().spawnPotentialsDefinition().isEmpty()) this.nextSpawnData = Optional.empty(); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 + this.resetStatistics(); + } + +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..192ee216b617d3533f592e62719b6d75d20b5a96 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 +@@ -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/src/main/java/net/minecraft/world/level/portal/TeleportTransition.java b/src/main/java/net/minecraft/world/level/portal/TeleportTransition.java +index cf27b0d6a9fe53b9f91090db4740776b335a2e9b..7d5909431f98f7e8b84d740bba9c044fec6d8e96 100644 +--- a/src/main/java/net/minecraft/world/level/portal/TeleportTransition.java ++++ b/src/main/java/net/minecraft/world/level/portal/TeleportTransition.java +@@ -53,7 +53,7 @@ public record TeleportTransition(ServerLevel newLevel, Vec3 position, Vec3 delta + } + + public TeleportTransition(ServerLevel worldserver, Entity entity, TeleportTransition.PostTeleportTransition teleporttransition_a, PlayerTeleportEvent.TeleportCause cause) { +- this(worldserver, findAdjustedSharedSpawnPos(worldserver, entity), Vec3.ZERO, 0.0F, 0.0F, false, false, Set.of(), teleporttransition_a, cause); ++ this(worldserver, findAdjustedSharedSpawnPos(worldserver, entity), Vec3.ZERO, worldserver.getSharedSpawnAngle(), 0.0F, false, false, Set.of(), teleporttransition_a, cause); // Paper - MC-200092 - fix first spawn pos yaw being ignored + // CraftBukkit end + } + +@@ -69,7 +69,7 @@ public record TeleportTransition(ServerLevel newLevel, Vec3 position, Vec3 delta + } + + public static TeleportTransition missingRespawnBlock(ServerLevel world, Entity entity, TeleportTransition.PostTeleportTransition postDimensionTransition) { +- return new TeleportTransition(world, findAdjustedSharedSpawnPos(world, entity), Vec3.ZERO, 0.0F, 0.0F, true, false, Set.of(), postDimensionTransition); ++ return new TeleportTransition(world, findAdjustedSharedSpawnPos(world, entity), Vec3.ZERO, world.getSharedSpawnAngle(), 0.0F, true, false, Set.of(), postDimensionTransition); // Paper - MC-200092 - fix spawn pos yaw being ignored + } + + private static Vec3 findAdjustedSharedSpawnPos(ServerLevel world, Entity entity) { diff --git a/patches/server/0734-Fix-a-bunch-of-vanilla-bugs.patch b/patches/server/0734-Fix-a-bunch-of-vanilla-bugs.patch deleted file mode 100644 index d1bf68f023..0000000000 --- a/patches/server/0734-Fix-a-bunch-of-vanilla-bugs.patch +++ /dev/null @@ -1,385 +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-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 -public net/minecraft/server/level/ChunkMap anyPlayerCloseEnoughForSpawning(Lnet/minecraft/world/level/ChunkPos;)Z - -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/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 32d368a18e14f247b4ddcb9d3dc16aa116359be4..03959bd6f40db9fb8f5da83377b8427ed0341f8a 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -754,7 +754,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 aeaf2d4f7a0ad0621c210cd479c610104ec7a83b..c078b3bc75e52456f458c7febc51ea6f8b29f737 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1889,7 +1889,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 91a3b9866e02414d2d71aa53ef1fb5fdecd8cd89..23929b165ff4ca153617c54d022ae43ef5fa258c 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..d431ee93cd7e87a24ff4079288facd089053d725 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, this.getDirection() == 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 c257660c79516a5919032b771fc3ac9575e9db9d..5d7f4e4f420c7e0a3467b7ec3859cae2eb63870f 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 7b63e2fd004ae452c7350f0b2d8d7c57a42891ea..5b2c7b8fb780e837d9d735ac86dcac949732ec69 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 -@@ -526,13 +526,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/TrialSpawner.java b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java -index 476caf7fb4f0124daa35822f2161e11620f18621..b6f9aca593a66fd1e18ab2c4d1989c08824fa6b4 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java -@@ -391,7 +391,7 @@ public final class TrialSpawner { - } - - public void overrideEntityToSpawn(EntityType entityType, Level world) { -- this.data.reset(); -+ this.data.reset(this); // Paper - this.normalConfig = Holder.direct(((TrialSpawnerConfig) this.normalConfig.value()).withSpawning(entityType)); - this.ominousConfig = Holder.direct(((TrialSpawnerConfig) this.ominousConfig.value()).withSpawning(entityType)); - this.setState(world, TrialSpawnerState.INACTIVE); -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 2f808e5f3a5fb2b63f273f6da47292cfd9719bcc..f4ba1afe2f4dc528fc154258d8bc9e144794980f 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 -@@ -100,9 +100,9 @@ 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(); -+ if (!logic.getConfig().spawnPotentialsDefinition().isEmpty()) this.nextSpawnData = Optional.empty(); // Paper - Fix TrialSpawner forgets assigned mob; MC-273635 - this.resetStatistics(); - } - -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..192ee216b617d3533f592e62719b6d75d20b5a96 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 -@@ -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/src/main/java/net/minecraft/world/level/portal/TeleportTransition.java b/src/main/java/net/minecraft/world/level/portal/TeleportTransition.java -index cf27b0d6a9fe53b9f91090db4740776b335a2e9b..7d5909431f98f7e8b84d740bba9c044fec6d8e96 100644 ---- a/src/main/java/net/minecraft/world/level/portal/TeleportTransition.java -+++ b/src/main/java/net/minecraft/world/level/portal/TeleportTransition.java -@@ -53,7 +53,7 @@ public record TeleportTransition(ServerLevel newLevel, Vec3 position, Vec3 delta - } - - public TeleportTransition(ServerLevel worldserver, Entity entity, TeleportTransition.PostTeleportTransition teleporttransition_a, PlayerTeleportEvent.TeleportCause cause) { -- this(worldserver, findAdjustedSharedSpawnPos(worldserver, entity), Vec3.ZERO, 0.0F, 0.0F, false, false, Set.of(), teleporttransition_a, cause); -+ this(worldserver, findAdjustedSharedSpawnPos(worldserver, entity), Vec3.ZERO, worldserver.getSharedSpawnAngle(), 0.0F, false, false, Set.of(), teleporttransition_a, cause); // Paper - MC-200092 - fix first spawn pos yaw being ignored - // CraftBukkit end - } - -@@ -69,7 +69,7 @@ public record TeleportTransition(ServerLevel newLevel, Vec3 position, Vec3 delta - } - - public static TeleportTransition missingRespawnBlock(ServerLevel world, Entity entity, TeleportTransition.PostTeleportTransition postDimensionTransition) { -- return new TeleportTransition(world, findAdjustedSharedSpawnPos(world, entity), Vec3.ZERO, 0.0F, 0.0F, true, false, Set.of(), postDimensionTransition); -+ return new TeleportTransition(world, findAdjustedSharedSpawnPos(world, entity), Vec3.ZERO, world.getSharedSpawnAngle(), 0.0F, true, false, Set.of(), postDimensionTransition); // Paper - MC-200092 - fix spawn pos yaw being ignored - } - - private static Vec3 findAdjustedSharedSpawnPos(ServerLevel world, Entity entity) { diff --git a/patches/server/0734-Remove-unnecessary-onTrackingStart-during-navigation.patch b/patches/server/0734-Remove-unnecessary-onTrackingStart-during-navigation.patch new file mode 100644 index 0000000000..3bc7296f88 --- /dev/null +++ b/patches/server/0734-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 d778f3dbe84b57f42703042ddd161e5c4bd4f14d..ad39671baae44714488eefbdbd4924824fd45fbc 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2252,7 +2252,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")); +@@ -2332,7 +2332,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/0735-Fix-custom-piglin-loved-items.patch b/patches/server/0735-Fix-custom-piglin-loved-items.patch new file mode 100644 index 0000000000..358bd47f1e --- /dev/null +++ b/patches/server/0735-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/0735-Remove-unnecessary-onTrackingStart-during-navigation.patch b/patches/server/0735-Remove-unnecessary-onTrackingStart-during-navigation.patch deleted file mode 100644 index 3bc7296f88..0000000000 --- a/patches/server/0735-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 d778f3dbe84b57f42703042ddd161e5c4bd4f14d..ad39671baae44714488eefbdbd4924824fd45fbc 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2252,7 +2252,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")); -@@ -2332,7 +2332,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/0736-EntityPickupItemEvent-fixes.patch b/patches/server/0736-EntityPickupItemEvent-fixes.patch new file mode 100644 index 0000000000..829f3de4fd --- /dev/null +++ b/patches/server/0736-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 5e64a6b94a510ed618a2542ad03e406a181b63d4..2121d2a2e1aa1d0f0390cc515317096431f6dcb0 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 +@@ -438,7 +438,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 6a7d9b59ff4aa2962a88ae8688c06bc67d70dfda..cee1e4db2312efb4843c4b6dc18f4af10b91d304 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/0736-Fix-custom-piglin-loved-items.patch b/patches/server/0736-Fix-custom-piglin-loved-items.patch deleted file mode 100644 index 358bd47f1e..0000000000 --- a/patches/server/0736-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/0737-Correctly-handle-interactions-with-items-on-cooldown.patch b/patches/server/0737-Correctly-handle-interactions-with-items-on-cooldown.patch new file mode 100644 index 0000000000..d902a451c9 --- /dev/null +++ b/patches/server/0737-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 fcc9fe8f5f57e9f6c28d762aa6585942e2b2698b..48d39015da2c91a27367d44e72b7dacddb41d6d6 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/0737-EntityPickupItemEvent-fixes.patch b/patches/server/0737-EntityPickupItemEvent-fixes.patch deleted file mode 100644 index 829f3de4fd..0000000000 --- a/patches/server/0737-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 5e64a6b94a510ed618a2542ad03e406a181b63d4..2121d2a2e1aa1d0f0390cc515317096431f6dcb0 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 -@@ -438,7 +438,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 6a7d9b59ff4aa2962a88ae8688c06bc67d70dfda..cee1e4db2312efb4843c4b6dc18f4af10b91d304 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/0738-Add-PlayerInventorySlotChangeEvent.patch b/patches/server/0738-Add-PlayerInventorySlotChangeEvent.patch new file mode 100644 index 0000000000..0c20c14c02 --- /dev/null +++ b/patches/server/0738-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 2821203352974f5bd1e873969f3bc64842761702..1dd593b7d90b29f238ef077753271b0d199c066c 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -379,6 +379,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/0738-Correctly-handle-interactions-with-items-on-cooldown.patch b/patches/server/0738-Correctly-handle-interactions-with-items-on-cooldown.patch deleted file mode 100644 index d902a451c9..0000000000 --- a/patches/server/0738-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 fcc9fe8f5f57e9f6c28d762aa6585942e2b2698b..48d39015da2c91a27367d44e72b7dacddb41d6d6 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/0739-Add-PlayerInventorySlotChangeEvent.patch b/patches/server/0739-Add-PlayerInventorySlotChangeEvent.patch deleted file mode 100644 index 69d629988b..0000000000 --- a/patches/server/0739-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 6236f5cbd32e9547bbb1312c322195e440dadc60..f6f1542657a6d96c34523ee3c3ab43586dd65e25 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -379,6 +379,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/0739-Elder-Guardian-appearance-API.patch b/patches/server/0739-Elder-Guardian-appearance-API.patch new file mode 100644 index 0000000000..fe6d385831 --- /dev/null +++ b/patches/server/0739-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 0bbd2c533f2c6f42464c058b1eea86d210cbdf93..38d3daba9715fdc73b59199f0aea09279799a25c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -3295,6 +3295,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/0740-Add-entity-knockback-API.patch b/patches/server/0740-Add-entity-knockback-API.patch new file mode 100644 index 0000000000..a9b58b4c8d --- /dev/null +++ b/patches/server/0740-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 9399df20ba14ad92379d5d2048e249883eaa8050..5efa27ab1e03eed4b2b05c4ea667b536ebc110bd 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/0740-Elder-Guardian-appearance-API.patch b/patches/server/0740-Elder-Guardian-appearance-API.patch deleted file mode 100644 index fe6d385831..0000000000 --- a/patches/server/0740-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 0bbd2c533f2c6f42464c058b1eea86d210cbdf93..38d3daba9715fdc73b59199f0aea09279799a25c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3295,6 +3295,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/0741-Add-entity-knockback-API.patch b/patches/server/0741-Add-entity-knockback-API.patch deleted file mode 100644 index a9b58b4c8d..0000000000 --- a/patches/server/0741-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 9399df20ba14ad92379d5d2048e249883eaa8050..5efa27ab1e03eed4b2b05c4ea667b536ebc110bd 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/0741-Detect-headless-JREs.patch b/patches/server/0741-Detect-headless-JREs.patch new file mode 100644 index 0000000000..6c876a6796 --- /dev/null +++ b/patches/server/0741-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 c551f6827476b6432ebe1d48e7ca5d168df305c5..16322471d83c461098a6ada11e790b9fba7b5ea2 100644 +--- a/src/main/java/net/minecraft/server/Main.java ++++ b/src/main/java/net/minecraft/server/Main.java +@@ -169,6 +169,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/0742-Detect-headless-JREs.patch b/patches/server/0742-Detect-headless-JREs.patch deleted file mode 100644 index 6c876a6796..0000000000 --- a/patches/server/0742-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 c551f6827476b6432ebe1d48e7ca5d168df305c5..16322471d83c461098a6ada11e790b9fba7b5ea2 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -169,6 +169,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/0742-fix-entity-vehicle-collision-event-not-called.patch b/patches/server/0742-fix-entity-vehicle-collision-event-not-called.patch new file mode 100644 index 0000000000..5511a3cdd1 --- /dev/null +++ b/patches/server/0742-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 7e7a78ebbf128f7d29cf9eb349f25230c9c7d5d0..f88c1becd08e7b10f228624160b85f89a379fbeb 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/0743-Add-EntityToggleSitEvent.patch b/patches/server/0743-Add-EntityToggleSitEvent.patch new file mode 100644 index 0000000000..375c8635da --- /dev/null +++ b/patches/server/0743-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 1c195c928fb5c165981665393424a64004331c93..5bcdeb3eb463d637b16abfb43d5489c0334b6673 100644 +--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +@@ -90,7 +90,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 +@@ -174,6 +174,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 7d9d4df95b5abbe340f813a9cb765e59e2bd6fae..d48c2bdb004c86e9e08680138fe51dc3b2975a64 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/0743-fix-entity-vehicle-collision-event-not-called.patch b/patches/server/0743-fix-entity-vehicle-collision-event-not-called.patch deleted file mode 100644 index 5511a3cdd1..0000000000 --- a/patches/server/0743-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 7e7a78ebbf128f7d29cf9eb349f25230c9c7d5d0..f88c1becd08e7b10f228624160b85f89a379fbeb 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/0744-Add-EntityToggleSitEvent.patch b/patches/server/0744-Add-EntityToggleSitEvent.patch deleted file mode 100644 index 375c8635da..0000000000 --- a/patches/server/0744-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 1c195c928fb5c165981665393424a64004331c93..5bcdeb3eb463d637b16abfb43d5489c0334b6673 100644 ---- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -@@ -90,7 +90,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 -@@ -174,6 +174,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 7d9d4df95b5abbe340f813a9cb765e59e2bd6fae..d48c2bdb004c86e9e08680138fe51dc3b2975a64 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/0744-Add-fire-tick-delay-option.patch b/patches/server/0744-Add-fire-tick-delay-option.patch new file mode 100644 index 0000000000..8e6c314b76 --- /dev/null +++ b/patches/server/0744-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 bd7835a8b470662b32cc28a4d8f777d4bb8dc60c..4535b514e808fa66318009455c465774b6a139be 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/0745-Add-Moving-Piston-API.patch b/patches/server/0745-Add-Moving-Piston-API.patch new file mode 100644 index 0000000000..e3d3955822 --- /dev/null +++ b/patches/server/0745-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 bd7835a8b470662b32cc28a4d8f777d4bb8dc60c..4535b514e808fa66318009455c465774b6a139be 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/0746-Add-Moving-Piston-API.patch b/patches/server/0746-Add-Moving-Piston-API.patch deleted file mode 100644 index e3d3955822..0000000000 --- a/patches/server/0746-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/0747-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch b/patches/server/0747-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch new file mode 100644 index 0000000000..2fe35c8b32 --- /dev/null +++ b/patches/server/0747-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/0747-Ignore-impossible-spawn-tick.patch b/patches/server/0747-Ignore-impossible-spawn-tick.patch deleted file mode 100644 index ee2750f36d..0000000000 --- a/patches/server/0747-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/0748-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch b/patches/server/0748-Fix-EntityArgument-and-EntitySelectorParser-permissi.patch deleted file mode 100644 index 2fe35c8b32..0000000000 --- a/patches/server/0748-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/0748-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch b/patches/server/0748-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch new file mode 100644 index 0000000000..693191cfdb --- /dev/null +++ b/patches/server/0748-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 41026637304430f1cbf4ed5dc1d44b807afa90af..584d658694ad23c0d047ca40208f766b9f44f8d6 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3351,6 +3351,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/0749-Add-PrePlayerAttackEntityEvent.patch b/patches/server/0749-Add-PrePlayerAttackEntityEvent.patch new file mode 100644 index 0000000000..5ca555ff3c --- /dev/null +++ b/patches/server/0749-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 81e3072ac80623db47ddc0b9c52e0e56dab9e10e..551f7c3750c87527ffc78545c99075221437d1dc 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -1225,8 +1225,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/0749-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch b/patches/server/0749-Fix-EntityCombustEvent-cancellation-cant-fully-preve.patch deleted file mode 100644 index 58f70904f6..0000000000 --- a/patches/server/0749-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 ad548e41740221fa5bb1aee6ba484e213bd1e779..0b55f92576a4257d210a53e9e77fcd573d558fc7 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3351,6 +3351,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/0750-Add-PrePlayerAttackEntityEvent.patch b/patches/server/0750-Add-PrePlayerAttackEntityEvent.patch deleted file mode 100644 index 5ca555ff3c..0000000000 --- a/patches/server/0750-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 81e3072ac80623db47ddc0b9c52e0e56dab9e10e..551f7c3750c87527ffc78545c99075221437d1dc 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -1225,8 +1225,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/0750-ensure-reset-EnderDragon-boss-event-name.patch b/patches/server/0750-ensure-reset-EnderDragon-boss-event-name.patch new file mode 100644 index 0000000000..4c5db1221b --- /dev/null +++ b/patches/server/0750-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/0751-Add-Player-Warden-Warning-API.patch b/patches/server/0751-Add-Player-Warden-Warning-API.patch new file mode 100644 index 0000000000..7edc6b34a9 --- /dev/null +++ b/patches/server/0751-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 38d3daba9715fdc73b59199f0aea09279799a25c..844ff0a4e75f7d2339327d20c6c9b87a354b64ec 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -3300,6 +3300,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/0751-ensure-reset-EnderDragon-boss-event-name.patch b/patches/server/0751-ensure-reset-EnderDragon-boss-event-name.patch deleted file mode 100644 index 4c5db1221b..0000000000 --- a/patches/server/0751-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/0752-Add-Player-Warden-Warning-API.patch b/patches/server/0752-Add-Player-Warden-Warning-API.patch deleted file mode 100644 index 7edc6b34a9..0000000000 --- a/patches/server/0752-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 38d3daba9715fdc73b59199f0aea09279799a25c..844ff0a4e75f7d2339327d20c6c9b87a354b64ec 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3300,6 +3300,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/0752-More-vanilla-friendly-methods-to-update-trades.patch b/patches/server/0752-More-vanilla-friendly-methods-to-update-trades.patch new file mode 100644 index 0000000000..54ee0482e2 --- /dev/null +++ b/patches/server/0752-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 27db2878073d1d77813574adfc54d1d686fc7088..af1aee3f6aefaa415601db5fd0bd461b84e68447 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/0753-Add-paper-dumplisteners-command.patch b/patches/server/0753-Add-paper-dumplisteners-command.patch new file mode 100644 index 0000000000..aabb60033d --- /dev/null +++ b/patches/server/0753-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/0753-More-vanilla-friendly-methods-to-update-trades.patch b/patches/server/0753-More-vanilla-friendly-methods-to-update-trades.patch deleted file mode 100644 index 54ee0482e2..0000000000 --- a/patches/server/0753-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 27db2878073d1d77813574adfc54d1d686fc7088..af1aee3f6aefaa415601db5fd0bd461b84e68447 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/0754-Add-paper-dumplisteners-command.patch b/patches/server/0754-Add-paper-dumplisteners-command.patch deleted file mode 100644 index aabb60033d..0000000000 --- a/patches/server/0754-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/0754-check-global-player-list-where-appropriate.patch b/patches/server/0754-check-global-player-list-where-appropriate.patch new file mode 100644 index 0000000000..2c629600b2 --- /dev/null +++ b/patches/server/0754-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 ad39671baae44714488eefbdbd4924824fd45fbc..8e72d36c2e2b5ff91b16188c95646b8447b6b2b8 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2368,4 +2368,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 28eb50111e524bce5aadb1dd2eea14a7df0105f2..26c25f9ccd59922ced968abef41683c2b6b45e7d 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3877,7 +3877,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 a5d13b8bf7d0b6423ef428042e1134f5999cc24b..30bce56a70f923b0ec77c8e3f29e435a71c71510 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 4bc3eded897b067e00c8e310c1be603aa7097ac4..84b6d88fdfe2cb8de297ef8a62cf923f004ee397 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/0755-Fix-async-entity-add-due-to-fungus-trees.patch b/patches/server/0755-Fix-async-entity-add-due-to-fungus-trees.patch new file mode 100644 index 0000000000..009feeb37a --- /dev/null +++ b/patches/server/0755-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/0755-check-global-player-list-where-appropriate.patch b/patches/server/0755-check-global-player-list-where-appropriate.patch deleted file mode 100644 index 2c629600b2..0000000000 --- a/patches/server/0755-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 ad39671baae44714488eefbdbd4924824fd45fbc..8e72d36c2e2b5ff91b16188c95646b8447b6b2b8 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2368,4 +2368,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 28eb50111e524bce5aadb1dd2eea14a7df0105f2..26c25f9ccd59922ced968abef41683c2b6b45e7d 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3877,7 +3877,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 a5d13b8bf7d0b6423ef428042e1134f5999cc24b..30bce56a70f923b0ec77c8e3f29e435a71c71510 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 4bc3eded897b067e00c8e310c1be603aa7097ac4..84b6d88fdfe2cb8de297ef8a62cf923f004ee397 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/0756-Fix-async-entity-add-due-to-fungus-trees.patch b/patches/server/0756-Fix-async-entity-add-due-to-fungus-trees.patch deleted file mode 100644 index 009feeb37a..0000000000 --- a/patches/server/0756-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/0756-ItemStack-damage-API.patch b/patches/server/0756-ItemStack-damage-API.patch new file mode 100644 index 0000000000..de20adcd15 --- /dev/null +++ b/patches/server/0756-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 679112d1622744680b7d3c7d296acafac019d00a..63872104e7302dbbc9c482a4ed8a9a34710e1eb4 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -698,8 +698,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 +@@ -731,7 +736,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 +@@ -771,6 +781,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) { +@@ -783,8 +798,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 5efa27ab1e03eed4b2b05c4ea667b536ebc110bd..20b84c87ef0987f76a4932f45a7d1534a74a8c00 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/0757-Friction-API.patch b/patches/server/0757-Friction-API.patch new file mode 100644 index 0000000000..2314f923e3 --- /dev/null +++ b/patches/server/0757-Friction-API.patch @@ -0,0 +1,245 @@ +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 26c25f9ccd59922ced968abef41683c2b6b45e7d..cdd94eb9b82bb22505461ae135d12914d7446b00 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -294,6 +294,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 d555fd0b200c012f30ed0c0ec09a37b25a737b76..7a6d51020d9c6be33b4c34c0d608559589d5b390 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/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java +index f88c1becd08e7b10f228624160b85f89a379fbeb..cdc8606ffe5c75ee19d92e9f86f26b2a502d765e 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java +@@ -93,6 +93,7 @@ public abstract class AbstractMinecart extends VehicleEntity { + private double flyingZ = 0.95; + public Double maxSpeed; + // CraftBukkit end ++ public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API + + protected AbstractMinecart(EntityType type, Level world) { + super(type, world); +@@ -552,6 +553,16 @@ public abstract class AbstractMinecart extends VehicleEntity { + + this.flipped = nbt.getBoolean("FlippedRotation"); + this.firstTick = nbt.getBoolean("HasTicked"); ++ // 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 + } + + @Override +@@ -564,6 +575,12 @@ public abstract class AbstractMinecart extends VehicleEntity { + + nbt.putBoolean("FlippedRotation", this.flipped); + nbt.putBoolean("HasTicked", this.firstTick); ++ ++ // 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 + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java b/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java +index 60b8d8c1ccfe7f9d1a327d1a361493e97ca9ad4c..f43439b31a14b9db4744512465d81134ebe5b3e1 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java +@@ -554,6 +554,7 @@ public class NewMinecartBehavior extends MinecartBehavior { + + @Override + public double getSlowdownFactor() { ++ if (this.minecart.frictionState == net.kyori.adventure.util.TriState.FALSE) return 1; // Paper + return this.minecart.isVehicle() || !this.minecart.slowWhenEmpty ? 0.997D : 0.975D; // CraftBukkit - add !this.slowWhenEmpty + } + +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java b/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java +index 62ae79808aba4112ea845311080bb496174a68d2..04a622f52353ebcc21f41c233f5a0fd67690cf4a 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java +@@ -528,6 +528,7 @@ public class OldMinecartBehavior extends MinecartBehavior { + + @Override + public double getSlowdownFactor() { ++ if (this.minecart.frictionState == net.kyori.adventure.util.TriState.FALSE) return 1; // Paper + return this.minecart.isVehicle() || !this.minecart.slowWhenEmpty ? 0.997D : 0.96D; // CraftBukkit - add !this.slowWhenEmpty + } + } +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 20b84c87ef0987f76a4932f45a7d1534a74a8c00..812194dac108e446cd987c474ec6e582eaaed32b 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/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java +index e02ecbdc158311bdc7e4d13307de6e2a2cf54235..b42bce0c4f4b3aac2729cfdad392d863245ed693 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java +@@ -127,4 +127,18 @@ public abstract class CraftMinecart extends CraftVehicle implements Minecart { + public int getDisplayBlockOffset() { + return this.getHandle().getDisplayOffset(); + } ++ ++ // 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/0757-ItemStack-damage-API.patch b/patches/server/0757-ItemStack-damage-API.patch deleted file mode 100644 index de20adcd15..0000000000 --- a/patches/server/0757-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 679112d1622744680b7d3c7d296acafac019d00a..63872104e7302dbbc9c482a4ed8a9a34710e1eb4 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -698,8 +698,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 -@@ -731,7 +736,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 -@@ -771,6 +781,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) { -@@ -783,8 +798,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 5efa27ab1e03eed4b2b05c4ea667b536ebc110bd..20b84c87ef0987f76a4932f45a7d1534a74a8c00 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/0758-Ability-to-control-player-s-insomnia-and-phantoms.patch b/patches/server/0758-Ability-to-control-player-s-insomnia-and-phantoms.patch new file mode 100644 index 0000000000..0b482955d5 --- /dev/null +++ b/patches/server/0758-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/0758-Friction-API.patch b/patches/server/0758-Friction-API.patch deleted file mode 100644 index 2314f923e3..0000000000 --- a/patches/server/0758-Friction-API.patch +++ /dev/null @@ -1,245 +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 26c25f9ccd59922ced968abef41683c2b6b45e7d..cdd94eb9b82bb22505461ae135d12914d7446b00 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -294,6 +294,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 d555fd0b200c012f30ed0c0ec09a37b25a737b76..7a6d51020d9c6be33b4c34c0d608559589d5b390 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/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -index f88c1becd08e7b10f228624160b85f89a379fbeb..cdc8606ffe5c75ee19d92e9f86f26b2a502d765e 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -@@ -93,6 +93,7 @@ public abstract class AbstractMinecart extends VehicleEntity { - private double flyingZ = 0.95; - public Double maxSpeed; - // CraftBukkit end -+ public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API - - protected AbstractMinecart(EntityType type, Level world) { - super(type, world); -@@ -552,6 +553,16 @@ public abstract class AbstractMinecart extends VehicleEntity { - - this.flipped = nbt.getBoolean("FlippedRotation"); - this.firstTick = nbt.getBoolean("HasTicked"); -+ // 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 - } - - @Override -@@ -564,6 +575,12 @@ public abstract class AbstractMinecart extends VehicleEntity { - - nbt.putBoolean("FlippedRotation", this.flipped); - nbt.putBoolean("HasTicked", this.firstTick); -+ -+ // 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 - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java b/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java -index 60b8d8c1ccfe7f9d1a327d1a361493e97ca9ad4c..f43439b31a14b9db4744512465d81134ebe5b3e1 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java -@@ -554,6 +554,7 @@ public class NewMinecartBehavior extends MinecartBehavior { - - @Override - public double getSlowdownFactor() { -+ if (this.minecart.frictionState == net.kyori.adventure.util.TriState.FALSE) return 1; // Paper - return this.minecart.isVehicle() || !this.minecart.slowWhenEmpty ? 0.997D : 0.975D; // CraftBukkit - add !this.slowWhenEmpty - } - -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java b/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java -index 62ae79808aba4112ea845311080bb496174a68d2..04a622f52353ebcc21f41c233f5a0fd67690cf4a 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java -@@ -528,6 +528,7 @@ public class OldMinecartBehavior extends MinecartBehavior { - - @Override - public double getSlowdownFactor() { -+ if (this.minecart.frictionState == net.kyori.adventure.util.TriState.FALSE) return 1; // Paper - return this.minecart.isVehicle() || !this.minecart.slowWhenEmpty ? 0.997D : 0.96D; // CraftBukkit - add !this.slowWhenEmpty - } - } -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 20b84c87ef0987f76a4932f45a7d1534a74a8c00..812194dac108e446cd987c474ec6e582eaaed32b 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/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java -index e02ecbdc158311bdc7e4d13307de6e2a2cf54235..b42bce0c4f4b3aac2729cfdad392d863245ed693 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java -@@ -127,4 +127,18 @@ public abstract class CraftMinecart extends CraftVehicle implements Minecart { - public int getDisplayBlockOffset() { - return this.getHandle().getDisplayOffset(); - } -+ -+ // 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/0759-Ability-to-control-player-s-insomnia-and-phantoms.patch b/patches/server/0759-Ability-to-control-player-s-insomnia-and-phantoms.patch deleted file mode 100644 index 0b482955d5..0000000000 --- a/patches/server/0759-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/0759-Fix-premature-player-kicks-on-shutdown.patch b/patches/server/0759-Fix-premature-player-kicks-on-shutdown.patch new file mode 100644 index 0000000000..7453334efc --- /dev/null +++ b/patches/server/0759-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 72e69f60fb687f102c963b61042b19162a5ec0b2..c12335bc83d31ec65fe2d7cbe0b084748e670010 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 b88a91ff85727109241991f76ebad7c0119ad436..0c44f59445e9cd5d2767cbabe874e137b2420a2d 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 72e69f60fb687f102c963b61042b19162a5ec0b2..c12335bc83d31ec65fe2d7cbe0b084748e670010 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 b88a91ff85727109241991f76ebad7c0119ad436..0c44f59445e9cd5d2767cbabe874e137b2420a2d 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: 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 1dd593b7d90b29f238ef077753271b0d199c066c..3a96eb35787ac4b45e4b212c221593516a32ea4d 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -348,6 +348,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/0761-Player-Entity-Tracking-Events.patch b/patches/server/0761-Player-Entity-Tracking-Events.patch new file mode 100644 index 0000000000..5bd2153391 --- /dev/null +++ b/patches/server/0761-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 2d325c998e40a65af10d6adbb0dc304bea50e3d8..c1c2eeba0f5b8e499cc51cc1df7bf9acb61bd7d6 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1580,7 +1580,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 584d658694ad23c0d047ca40208f766b9f44f8d6..59dd5179b3ac6e448304a94d1e6343b3c08d674d 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -4106,7 +4106,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/0761-Sync-offhand-slot-in-menus.patch b/patches/server/0761-Sync-offhand-slot-in-menus.patch deleted file mode 100644 index 32cd4e42b8..0000000000 --- a/patches/server/0761-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 f6f1542657a6d96c34523ee3c3ab43586dd65e25..a62e16b88a400c0715ddbdc33d25663303cc9103 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -348,6 +348,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/0762-Limit-pet-look-distance.patch b/patches/server/0762-Limit-pet-look-distance.patch new file mode 100644 index 0000000000..983f861539 --- /dev/null +++ b/patches/server/0762-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/0762-Player-Entity-Tracking-Events.patch b/patches/server/0762-Player-Entity-Tracking-Events.patch deleted file mode 100644 index 3cbe275c83..0000000000 --- a/patches/server/0762-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 2d325c998e40a65af10d6adbb0dc304bea50e3d8..c1c2eeba0f5b8e499cc51cc1df7bf9acb61bd7d6 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1580,7 +1580,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 0b55f92576a4257d210a53e9e77fcd573d558fc7..827f141834ac903adca919f3514a468b7b6de089 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4106,7 +4106,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/0763-Limit-pet-look-distance.patch b/patches/server/0763-Limit-pet-look-distance.patch deleted file mode 100644 index 983f861539..0000000000 --- a/patches/server/0763-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/0763-fix-Instruments.patch b/patches/server/0763-fix-Instruments.patch new file mode 100644 index 0000000000..8e1919eba3 --- /dev/null +++ b/patches/server/0763-fix-Instruments.patch @@ -0,0 +1,83 @@ +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 844ff0a4e75f7d2339327d20c6c9b87a354b64ec..68329d971594ed24438b9398a5a4219a71aed28d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -775,7 +775,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/src/test/java/org/bukkit/InstrumentTest.java b/src/test/java/org/bukkit/InstrumentTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5da6b5c996c9a4077f309e923731e3f148e91c19 +--- /dev/null ++++ b/src/test/java/org/bukkit/InstrumentTest.java +@@ -0,0 +1,20 @@ ++package org.bukkit; ++ ++import org.bukkit.support.environment.AllFeatures; ++import org.junit.jupiter.api.Test; ++ ++import static org.bukkit.support.MatcherAssert.assertThat; ++import static org.hamcrest.CoreMatchers.is; ++ ++@AllFeatures ++public class InstrumentTest { // Paper - moved to internals as this test now access the sound registry. ++ ++ @Test ++ public void getByType() { ++ for (Instrument instrument : Instrument.values()) { ++ // Paper - byte magic values are still used ++ ++ assertThat(Instrument.getByType(instrument.getType()), is(instrument)); ++ } ++ } ++} diff --git a/patches/server/0764-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch b/patches/server/0764-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch new file mode 100644 index 0000000000..12e018cb68 --- /dev/null +++ b/patches/server/0764-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 c3494c5fca138cde1f48e07d8c42ed32254a0d17..7e62dcef2902463c7f67aa20cdb78ea9cf4c44f6 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 +@@ -973,15 +973,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; + } + +@@ -1059,7 +1059,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; + } + +@@ -1280,11 +1280,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/0764-fix-Instruments.patch b/patches/server/0764-fix-Instruments.patch deleted file mode 100644 index 8e1919eba3..0000000000 --- a/patches/server/0764-fix-Instruments.patch +++ /dev/null @@ -1,83 +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 844ff0a4e75f7d2339327d20c6c9b87a354b64ec..68329d971594ed24438b9398a5a4219a71aed28d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -775,7 +775,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/src/test/java/org/bukkit/InstrumentTest.java b/src/test/java/org/bukkit/InstrumentTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5da6b5c996c9a4077f309e923731e3f148e91c19 ---- /dev/null -+++ b/src/test/java/org/bukkit/InstrumentTest.java -@@ -0,0 +1,20 @@ -+package org.bukkit; -+ -+import org.bukkit.support.environment.AllFeatures; -+import org.junit.jupiter.api.Test; -+ -+import static org.bukkit.support.MatcherAssert.assertThat; -+import static org.hamcrest.CoreMatchers.is; -+ -+@AllFeatures -+public class InstrumentTest { // Paper - moved to internals as this test now access the sound registry. -+ -+ @Test -+ public void getByType() { -+ for (Instrument instrument : Instrument.values()) { -+ // Paper - byte magic values are still used -+ -+ assertThat(Instrument.getByType(instrument.getType()), is(instrument)); -+ } -+ } -+} diff --git a/patches/server/0765-Add-BlockLockCheckEvent.patch b/patches/server/0765-Add-BlockLockCheckEvent.patch new file mode 100644 index 0000000000..b06f734eb2 --- /dev/null +++ b/patches/server/0765-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/0765-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch b/patches/server/0765-Improve-inlining-for-some-hot-BlockBehavior-and-Flui.patch deleted file mode 100644 index 12e018cb68..0000000000 --- a/patches/server/0765-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 c3494c5fca138cde1f48e07d8c42ed32254a0d17..7e62dcef2902463c7f67aa20cdb78ea9cf4c44f6 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 -@@ -973,15 +973,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; - } - -@@ -1059,7 +1059,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; - } - -@@ -1280,11 +1280,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/0766-Add-BlockLockCheckEvent.patch b/patches/server/0766-Add-BlockLockCheckEvent.patch deleted file mode 100644 index b06f734eb2..0000000000 --- a/patches/server/0766-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/0766-Add-Sneaking-API-for-Entities.patch b/patches/server/0766-Add-Sneaking-API-for-Entities.patch new file mode 100644 index 0000000000..a4f307c126 --- /dev/null +++ b/patches/server/0766-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 1edccd83ecc498ebc07c3c6ca019eeb28c897973..0e65361b6a7371086f1ee471603209a1a347e3de 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -870,6 +870,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/0767-Add-Sneaking-API-for-Entities.patch b/patches/server/0767-Add-Sneaking-API-for-Entities.patch deleted file mode 100644 index a4f307c126..0000000000 --- a/patches/server/0767-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 1edccd83ecc498ebc07c3c6ca019eeb28c897973..0e65361b6a7371086f1ee471603209a1a347e3de 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -870,6 +870,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/0767-Improve-logging-and-errors.patch b/patches/server/0767-Improve-logging-and-errors.patch new file mode 100644 index 0000000000..aec88d7e1b --- /dev/null +++ b/patches/server/0767-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 611081844ea18361d0219ab94ba3f5f72c63cf6b..debd90fda75048f5352e7cddaeeb8121ed74b19c 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/0768-Improve-PortalEvents.patch b/patches/server/0768-Improve-PortalEvents.patch new file mode 100644 index 0000000000..f69655a373 --- /dev/null +++ b/patches/server/0768-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 3a96eb35787ac4b45e4b212c221593516a32ea4d..07f14652768d4715eb9053b5a8381816a61b0d28 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1552,7 +1552,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 59dd5179b3ac6e448304a94d1e6343b3c08d674d..1fa9a243c883120402ecc191d98a750b742bdbd0 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3777,7 +3777,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 58b2454ac5bd3400559aba3c64f228f41f6218ae..af46f2885ead1e3ec1734504d8ba134c886e04fb 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 8ca226641588a88c8b068a7acac9d7e92b077144..8cb4142562db0be1f1a7d961ec5a10d4abf31692 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 ac894e5651ea6145727639e2882edb236a47fb02..3e9642e5236d9a1cc8e8f3b375d76810f4bc7c6c 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/0768-Improve-logging-and-errors.patch b/patches/server/0768-Improve-logging-and-errors.patch deleted file mode 100644 index aec88d7e1b..0000000000 --- a/patches/server/0768-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 611081844ea18361d0219ab94ba3f5f72c63cf6b..debd90fda75048f5352e7cddaeeb8121ed74b19c 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/0769-Add-config-option-for-spider-worldborder-climbing.patch b/patches/server/0769-Add-config-option-for-spider-worldborder-climbing.patch new file mode 100644 index 0000000000..6d4efc38b6 --- /dev/null +++ b/patches/server/0769-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/0769-Improve-PortalEvents.patch b/patches/server/0769-Improve-PortalEvents.patch deleted file mode 100644 index 88802cbfdd..0000000000 --- a/patches/server/0769-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 a62e16b88a400c0715ddbdc33d25663303cc9103..a5eaac3fb6d949098a9fca20d9dbff59c56773ed 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1552,7 +1552,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 827f141834ac903adca919f3514a468b7b6de089..1f9379ac11b15b564e70fcab655bc5e50b584e65 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3777,7 +3777,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 58b2454ac5bd3400559aba3c64f228f41f6218ae..af46f2885ead1e3ec1734504d8ba134c886e04fb 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 8ca226641588a88c8b068a7acac9d7e92b077144..8cb4142562db0be1f1a7d961ec5a10d4abf31692 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 ac894e5651ea6145727639e2882edb236a47fb02..3e9642e5236d9a1cc8e8f3b375d76810f4bc7c6c 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/0770-Add-config-option-for-spider-worldborder-climbing.patch b/patches/server/0770-Add-config-option-for-spider-worldborder-climbing.patch deleted file mode 100644 index 6d4efc38b6..0000000000 --- a/patches/server/0770-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/0770-Add-missing-SpigotConfig-logCommands-check.patch b/patches/server/0770-Add-missing-SpigotConfig-logCommands-check.patch new file mode 100644 index 0000000000..a8a18cd319 --- /dev/null +++ b/patches/server/0770-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 ce818321177df69ee81a9a237f2f44216ecea640..0c7fa826ee3f7a0851b49487484eb2ca39d9fcd7 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2139,7 +2139,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); +@@ -2179,7 +2181,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/0771-Add-missing-SpigotConfig-logCommands-check.patch b/patches/server/0771-Add-missing-SpigotConfig-logCommands-check.patch deleted file mode 100644 index a8a18cd319..0000000000 --- a/patches/server/0771-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 ce818321177df69ee81a9a237f2f44216ecea640..0c7fa826ee3f7a0851b49487484eb2ca39d9fcd7 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2139,7 +2139,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); -@@ -2179,7 +2181,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/0771-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch b/patches/server/0771-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch new file mode 100644 index 0000000000..581ad00ec1 --- /dev/null +++ b/patches/server/0771-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/0772-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch b/patches/server/0772-Fix-NPE-on-Allay-stopDancing-while-not-dancing.patch deleted file mode 100644 index 581ad00ec1..0000000000 --- a/patches/server/0772-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/0772-Flying-Fall-Damage.patch b/patches/server/0772-Flying-Fall-Damage.patch new file mode 100644 index 0000000000..d74e2cad08 --- /dev/null +++ b/patches/server/0772-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 551f7c3750c87527ffc78545c99075221437d1dc..7dd601d0b0efd285a913a074ffa42e142bda8889 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -199,6 +199,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; +@@ -1654,7 +1655,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 68329d971594ed24438b9398a5a4219a71aed28d..c00cf53b7b7b6d8b1ecd582c49fe82263920f0df 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -2593,6 +2593,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 void setFlySpeed(float value) { + this.validateSpeed(value); diff --git a/patches/server/0773-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch b/patches/server/0773-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch new file mode 100644 index 0000000000..2ab3512daf --- /dev/null +++ b/patches/server/0773-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 1fa9a243c883120402ecc191d98a750b742bdbd0..7897bec4aa04c93793af819cfaf8a7a751c4f1e4 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -977,6 +977,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 { +@@ -1071,7 +1072,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/0773-Flying-Fall-Damage.patch b/patches/server/0773-Flying-Fall-Damage.patch deleted file mode 100644 index d74e2cad08..0000000000 --- a/patches/server/0773-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 551f7c3750c87527ffc78545c99075221437d1dc..7dd601d0b0efd285a913a074ffa42e142bda8889 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -199,6 +199,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; -@@ -1654,7 +1655,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 68329d971594ed24438b9398a5a4219a71aed28d..c00cf53b7b7b6d8b1ecd582c49fe82263920f0df 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2593,6 +2593,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 void setFlySpeed(float value) { - this.validateSpeed(value); diff --git a/patches/server/0774-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch b/patches/server/0774-Expose-pre-collision-moving-velocity-to-VehicleBlock.patch deleted file mode 100644 index 35080d56e0..0000000000 --- a/patches/server/0774-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 1f9379ac11b15b564e70fcab655bc5e50b584e65..5b2341e07d66feb4a3975eb2eb6208306c3ebaa9 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -977,6 +977,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 { -@@ -1071,7 +1072,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/0774-config-for-disabling-entity-tag-tags.patch b/patches/server/0774-config-for-disabling-entity-tag-tags.patch new file mode 100644 index 0000000000..70bef01fe4 --- /dev/null +++ b/patches/server/0774-config-for-disabling-entity-tag-tags.patch @@ -0,0 +1,26 @@ +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 d62c17c01f39d41d7cd422d37326a66791804090..979c99851ccb363d889069bafa5b5f7eb6b1a436 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityType.java ++++ b/src/main/java/net/minecraft/world/entity/EntityType.java +@@ -579,6 +579,15 @@ public class EntityType implements FeatureElement, EntityTypeT + + if (entity.getType() == entitytypes) { + if (world.isClientSide || !entity.getType().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/0775-Use-single-player-info-update-packet-on-join.patch b/patches/server/0775-Use-single-player-info-update-packet-on-join.patch new file mode 100644 index 0000000000..3bef6e1531 --- /dev/null +++ b/patches/server/0775-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 0c7fa826ee3f7a0851b49487484eb2ca39d9fcd7..2cd5ddcd99e77b6e28469a84d6b171b0c099819e 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -3540,7 +3540,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 23929b165ff4ca153617c54d022ae43ef5fa258c..28ca991e89fc0c651220c65cb939f9ebb12d9c93 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/0775-config-for-disabling-entity-tag-tags.patch b/patches/server/0775-config-for-disabling-entity-tag-tags.patch deleted file mode 100644 index 70bef01fe4..0000000000 --- a/patches/server/0775-config-for-disabling-entity-tag-tags.patch +++ /dev/null @@ -1,26 +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 d62c17c01f39d41d7cd422d37326a66791804090..979c99851ccb363d889069bafa5b5f7eb6b1a436 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -579,6 +579,15 @@ public class EntityType implements FeatureElement, EntityTypeT - - if (entity.getType() == entitytypes) { - if (world.isClientSide || !entity.getType().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/0776-Correctly-shrink-items-during-EntityResurrectEvent.patch b/patches/server/0776-Correctly-shrink-items-during-EntityResurrectEvent.patch new file mode 100644 index 0000000000..f16e8a752f --- /dev/null +++ b/patches/server/0776-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 cdd94eb9b82bb22505461ae135d12914d7446b00..1c67dafa4a54513d2f8febd13124ea5c976b313e 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -1683,7 +1683,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/0776-Use-single-player-info-update-packet-on-join.patch b/patches/server/0776-Use-single-player-info-update-packet-on-join.patch deleted file mode 100644 index 3bef6e1531..0000000000 --- a/patches/server/0776-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 0c7fa826ee3f7a0851b49487484eb2ca39d9fcd7..2cd5ddcd99e77b6e28469a84d6b171b0c099819e 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3540,7 +3540,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 23929b165ff4ca153617c54d022ae43ef5fa258c..28ca991e89fc0c651220c65cb939f9ebb12d9c93 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/0777-Correctly-shrink-items-during-EntityResurrectEvent.patch b/patches/server/0777-Correctly-shrink-items-during-EntityResurrectEvent.patch deleted file mode 100644 index f16e8a752f..0000000000 --- a/patches/server/0777-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 cdd94eb9b82bb22505461ae135d12914d7446b00..1c67dafa4a54513d2f8febd13124ea5c976b313e 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1683,7 +1683,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/0777-Win-Screen-API.patch b/patches/server/0777-Win-Screen-API.patch new file mode 100644 index 0000000000..1b79652c2a --- /dev/null +++ b/patches/server/0777-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 c00cf53b7b7b6d8b1ecd582c49fe82263920f0df..809b1ead09246281fc09d5cbdaa2ad4432e13978 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1312,6 +1312,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/0778-Remove-CraftItemStack-setAmount-null-assignment.patch b/patches/server/0778-Remove-CraftItemStack-setAmount-null-assignment.patch new file mode 100644 index 0000000000..aa0acd564f --- /dev/null +++ b/patches/server/0778-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/0778-Win-Screen-API.patch b/patches/server/0778-Win-Screen-API.patch deleted file mode 100644 index 1b79652c2a..0000000000 --- a/patches/server/0778-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 c00cf53b7b7b6d8b1ecd582c49fe82263920f0df..809b1ead09246281fc09d5cbdaa2ad4432e13978 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1312,6 +1312,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/0779-Fix-force-opening-enchantment-tables.patch b/patches/server/0779-Fix-force-opening-enchantment-tables.patch new file mode 100644 index 0000000000..deac4001bb --- /dev/null +++ b/patches/server/0779-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 aa3a47149fec342096817c7b9ce45ea196fd33d0..9509fa35ccf6f1f6fe24250bad8095b6ccdad6b0 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/0779-Remove-CraftItemStack-setAmount-null-assignment.patch b/patches/server/0779-Remove-CraftItemStack-setAmount-null-assignment.patch deleted file mode 100644 index aa0acd564f..0000000000 --- a/patches/server/0779-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/0780-Add-Entity-Body-Yaw-API.patch b/patches/server/0780-Add-Entity-Body-Yaw-API.patch new file mode 100644 index 0000000000..e46f48b4ac --- /dev/null +++ b/patches/server/0780-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 0e65361b6a7371086f1ee471603209a1a347e3de..f1992713a9e61a9e3cd719d4676f4c3f2917435d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1179,6 +1179,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 812194dac108e446cd987c474ec6e582eaaed32b..cf388e227cd5893619ab5d05fee4a43c00ba0d9a 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/0780-Fix-force-opening-enchantment-tables.patch b/patches/server/0780-Fix-force-opening-enchantment-tables.patch deleted file mode 100644 index deac4001bb..0000000000 --- a/patches/server/0780-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 aa3a47149fec342096817c7b9ce45ea196fd33d0..9509fa35ccf6f1f6fe24250bad8095b6ccdad6b0 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/0781-Add-Entity-Body-Yaw-API.patch b/patches/server/0781-Add-Entity-Body-Yaw-API.patch deleted file mode 100644 index e46f48b4ac..0000000000 --- a/patches/server/0781-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 0e65361b6a7371086f1ee471603209a1a347e3de..f1992713a9e61a9e3cd719d4676f4c3f2917435d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1179,6 +1179,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 812194dac108e446cd987c474ec6e582eaaed32b..cf388e227cd5893619ab5d05fee4a43c00ba0d9a 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/0781-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch b/patches/server/0781-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch new file mode 100644 index 0000000000..c3a7139e9a --- /dev/null +++ b/patches/server/0781-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 9bc37686eb44ad295e7675daf3c00a8fbbed65b9..41f4107101bcd5d753b72cdbabe7946a1975c653 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 +@@ -42,7 +42,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( diff --git a/patches/server/0782-Add-EntityFertilizeEggEvent.patch b/patches/server/0782-Add-EntityFertilizeEggEvent.patch new file mode 100644 index 0000000000..5cca5ebf89 --- /dev/null +++ b/patches/server/0782-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 b44b9f77dd8d36ac1e0245820fbc6b91974be4b2..ca04e5d829331551a2c2f44e223ff05c6ce04e76 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 48d39015da2c91a27367d44e72b7dacddb41d6d6..ec5c16f64d4e797b4c09bd0d3ae6f143d8795612 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/0782-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch b/patches/server/0782-Fix-MC-157464-Prevent-sleeping-villagers-moving-towa.patch deleted file mode 100644 index c3a7139e9a..0000000000 --- a/patches/server/0782-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 9bc37686eb44ad295e7675daf3c00a8fbbed65b9..41f4107101bcd5d753b72cdbabe7946a1975c653 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 -@@ -42,7 +42,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( diff --git a/patches/server/0783-Add-EntityFertilizeEggEvent.patch b/patches/server/0783-Add-EntityFertilizeEggEvent.patch deleted file mode 100644 index 5cca5ebf89..0000000000 --- a/patches/server/0783-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 b44b9f77dd8d36ac1e0245820fbc6b91974be4b2..ca04e5d829331551a2c2f44e223ff05c6ce04e76 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 48d39015da2c91a27367d44e72b7dacddb41d6d6..ec5c16f64d4e797b4c09bd0d3ae6f143d8795612 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/0783-Fix-HumanEntity-drop-not-updating-the-client-inv.patch b/patches/server/0783-Fix-HumanEntity-drop-not-updating-the-client-inv.patch new file mode 100644 index 0000000000..5807cdf697 --- /dev/null +++ b/patches/server/0783-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 9509fa35ccf6f1f6fe24250bad8095b6ccdad6b0..db99af60c8145cc62f368b06bbc283f24d4dbfb2 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/0784-Add-CompostItemEvent-and-EntityCompostItemEvent.patch b/patches/server/0784-Add-CompostItemEvent-and-EntityCompostItemEvent.patch new file mode 100644 index 0000000000..f182b8195b --- /dev/null +++ b/patches/server/0784-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 b4937f04b4cae1ddff8d6df0f608b2f2e3fb367c..9264ba58188a7a682eeb8eb449b89ff8e60f91d6 100644 +--- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java +@@ -342,7 +342,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; +@@ -491,6 +505,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/0784-Fix-HumanEntity-drop-not-updating-the-client-inv.patch b/patches/server/0784-Fix-HumanEntity-drop-not-updating-the-client-inv.patch deleted file mode 100644 index 5807cdf697..0000000000 --- a/patches/server/0784-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 9509fa35ccf6f1f6fe24250bad8095b6ccdad6b0..db99af60c8145cc62f368b06bbc283f24d4dbfb2 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/0785-Add-CompostItemEvent-and-EntityCompostItemEvent.patch b/patches/server/0785-Add-CompostItemEvent-and-EntityCompostItemEvent.patch deleted file mode 100644 index f182b8195b..0000000000 --- a/patches/server/0785-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 b4937f04b4cae1ddff8d6df0f608b2f2e3fb367c..9264ba58188a7a682eeb8eb449b89ff8e60f91d6 100644 ---- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -@@ -342,7 +342,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; -@@ -491,6 +505,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/0785-Correctly-handle-ArmorStand-invisibility.patch b/patches/server/0785-Correctly-handle-ArmorStand-invisibility.patch new file mode 100644 index 0000000000..4c4c5048be --- /dev/null +++ b/patches/server/0785-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/0786-Correctly-handle-ArmorStand-invisibility.patch b/patches/server/0786-Correctly-handle-ArmorStand-invisibility.patch deleted file mode 100644 index 4c4c5048be..0000000000 --- a/patches/server/0786-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/0786-Fix-advancement-triggers-for-entity-damage.patch b/patches/server/0786-Fix-advancement-triggers-for-entity-damage.patch new file mode 100644 index 0000000000..ce38a29549 --- /dev/null +++ b/patches/server/0786-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 2fb95271a161a30ce6f8ce40cc75470db3d03c4a..c838dc018fad67ae0a9b602a3b477aaea137bca2 100644 +--- a/src/main/java/net/minecraft/world/entity/Interaction.java ++++ b/src/main/java/net/minecraft/world/entity/Interaction.java +@@ -160,7 +160,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 1c67dafa4a54513d2f8febd13124ea5c976b313e..4e0eb1f0103823a764c184142744a290c0ebed53 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -2475,7 +2475,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)); +@@ -2483,7 +2483,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/0787-Fix-advancement-triggers-for-entity-damage.patch b/patches/server/0787-Fix-advancement-triggers-for-entity-damage.patch deleted file mode 100644 index ce38a29549..0000000000 --- a/patches/server/0787-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 2fb95271a161a30ce6f8ce40cc75470db3d03c4a..c838dc018fad67ae0a9b602a3b477aaea137bca2 100644 ---- a/src/main/java/net/minecraft/world/entity/Interaction.java -+++ b/src/main/java/net/minecraft/world/entity/Interaction.java -@@ -160,7 +160,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 1c67dafa4a54513d2f8febd13124ea5c976b313e..4e0eb1f0103823a764c184142744a290c0ebed53 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2475,7 +2475,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)); -@@ -2483,7 +2483,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/0787-Fix-text-display-error-on-spawn.patch b/patches/server/0787-Fix-text-display-error-on-spawn.patch new file mode 100644 index 0000000000..d783ac8eee --- /dev/null +++ b/patches/server/0787-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/0788-Fix-inventories-returning-null-Locations.patch b/patches/server/0788-Fix-inventories-returning-null-Locations.patch new file mode 100644 index 0000000000..715c9ff910 --- /dev/null +++ b/patches/server/0788-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 5d7f4e4f420c7e0a3467b7ec3859cae2eb63870f..75f097414f436eee9f179d4d03dd64599cbaad6f 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/0788-Fix-text-display-error-on-spawn.patch b/patches/server/0788-Fix-text-display-error-on-spawn.patch deleted file mode 100644 index d783ac8eee..0000000000 --- a/patches/server/0788-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/0789-Add-Shearable-API.patch b/patches/server/0789-Add-Shearable-API.patch new file mode 100644 index 0000000000..302cec90c2 --- /dev/null +++ b/patches/server/0789-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/0789-Fix-inventories-returning-null-Locations.patch b/patches/server/0789-Fix-inventories-returning-null-Locations.patch deleted file mode 100644 index 715c9ff910..0000000000 --- a/patches/server/0789-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 5d7f4e4f420c7e0a3467b7ec3859cae2eb63870f..75f097414f436eee9f179d4d03dd64599cbaad6f 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/0790-Add-Shearable-API.patch b/patches/server/0790-Add-Shearable-API.patch deleted file mode 100644 index 302cec90c2..0000000000 --- a/patches/server/0790-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/0790-Fix-SpawnEggMeta-get-setSpawnedType.patch b/patches/server/0790-Fix-SpawnEggMeta-get-setSpawnedType.patch new file mode 100644 index 0000000000..254a94df3a --- /dev/null +++ b/patches/server/0790-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/0791-Fix-SpawnEggMeta-get-setSpawnedType.patch b/patches/server/0791-Fix-SpawnEggMeta-get-setSpawnedType.patch deleted file mode 100644 index 254a94df3a..0000000000 --- a/patches/server/0791-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/0791-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch b/patches/server/0791-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch new file mode 100644 index 0000000000..16390f90c4 --- /dev/null +++ b/patches/server/0791-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 5b2c7b8fb780e837d9d735ac86dcac949732ec69..5fe0879efb35970e49d0654c4cb27195c6cc88a4 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 +@@ -494,6 +494,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/0792-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch b/patches/server/0792-Fix-crash-relating-to-bad-recipes-in-furnace-like-ti.patch deleted file mode 100644 index 16390f90c4..0000000000 --- a/patches/server/0792-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 5b2c7b8fb780e837d9d735ac86dcac949732ec69..5fe0879efb35970e49d0654c4cb27195c6cc88a4 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 -@@ -494,6 +494,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/0792-Treat-sequence-violations-like-they-should-be.patch b/patches/server/0792-Treat-sequence-violations-like-they-should-be.patch new file mode 100644 index 0000000000..68d70efd4d --- /dev/null +++ b/patches/server/0792-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 2cd5ddcd99e77b6e28469a84d6b171b0c099819e..0545414171c65531a39d6c4f4f3ea669bd8214ee 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2058,6 +2058,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/0793-Prevent-causing-expired-keys-from-impacting-new-join.patch b/patches/server/0793-Prevent-causing-expired-keys-from-impacting-new-join.patch new file mode 100644 index 0000000000..f86d440282 --- /dev/null +++ b/patches/server/0793-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 ef33705588abf550e2b3d0bf795788516141b3df..6bfb83434a184e6fdba932f692281f0303ada65f 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java +@@ -116,7 +116,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 0545414171c65531a39d6c4f4f3ea669bd8214ee..13b71e5572f68f5992bc95638c11a4f6a8e18099 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -307,6 +307,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(); +@@ -403,6 +404,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) { +@@ -3538,6 +3546,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/0793-Treat-sequence-violations-like-they-should-be.patch b/patches/server/0793-Treat-sequence-violations-like-they-should-be.patch deleted file mode 100644 index 68d70efd4d..0000000000 --- a/patches/server/0793-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 2cd5ddcd99e77b6e28469a84d6b171b0c099819e..0545414171c65531a39d6c4f4f3ea669bd8214ee 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2058,6 +2058,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/0794-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch b/patches/server/0794-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch new file mode 100644 index 0000000000..a1e0e51950 --- /dev/null +++ b/patches/server/0794-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 8e72d36c2e2b5ff91b16188c95646b8447b6b2b8..1242ddeb98c5a0582591a071ef615f726f6aa132 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1361,6 +1361,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/0794-Prevent-causing-expired-keys-from-impacting-new-join.patch b/patches/server/0794-Prevent-causing-expired-keys-from-impacting-new-join.patch deleted file mode 100644 index f86d440282..0000000000 --- a/patches/server/0794-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 ef33705588abf550e2b3d0bf795788516141b3df..6bfb83434a184e6fdba932f692281f0303ada65f 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -@@ -116,7 +116,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 0545414171c65531a39d6c4f4f3ea669bd8214ee..13b71e5572f68f5992bc95638c11a4f6a8e18099 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -307,6 +307,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(); -@@ -403,6 +404,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) { -@@ -3538,6 +3546,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/0795-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch b/patches/server/0795-Prevent-GameEvents-being-fired-from-unloaded-chunks.patch deleted file mode 100644 index 2339341967..0000000000 --- a/patches/server/0795-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 334b21a37196f4bf1046d9506c9a491d2662adad..362e4466f443a9c1a04bda74f7c60f7df8944169 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1361,6 +1361,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/0795-Use-array-for-gamerule-storage.patch b/patches/server/0795-Use-array-for-gamerule-storage.patch new file mode 100644 index 0000000000..efb6cfeb50 --- /dev/null +++ b/patches/server/0795-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/0796-Fix-a-couple-of-upstream-bed-issues.patch b/patches/server/0796-Fix-a-couple-of-upstream-bed-issues.patch new file mode 100644 index 0000000000..d47a0b12c8 --- /dev/null +++ b/patches/server/0796-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 30db6ae29e2fe03866dfa656330f7341e0a3f9ab..be700995c3e7f63e0471712c3cd6fd83db583491 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/0796-Use-array-for-gamerule-storage.patch b/patches/server/0796-Use-array-for-gamerule-storage.patch deleted file mode 100644 index efb6cfeb50..0000000000 --- a/patches/server/0796-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/0797-Fix-a-couple-of-upstream-bed-issues.patch b/patches/server/0797-Fix-a-couple-of-upstream-bed-issues.patch deleted file mode 100644 index d47a0b12c8..0000000000 --- a/patches/server/0797-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 30db6ae29e2fe03866dfa656330f7341e0a3f9ab..be700995c3e7f63e0471712c3cd6fd83db583491 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/0797-Fix-demo-flag-not-enabling-demo-mode.patch b/patches/server/0797-Fix-demo-flag-not-enabling-demo-mode.patch new file mode 100644 index 0000000000..db1ba5d6f6 --- /dev/null +++ b/patches/server/0797-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 16322471d83c461098a6ada11e790b9fba7b5ea2..731bdabd53fd4a3d17494f26781223097a5d6e16 100644 +--- a/src/main/java/net/minecraft/server/Main.java ++++ b/src/main/java/net/minecraft/server/Main.java +@@ -327,7 +327,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/0798-Add-Mob-Experience-reward-API.patch b/patches/server/0798-Add-Mob-Experience-reward-API.patch new file mode 100644 index 0000000000..9e59c458f8 --- /dev/null +++ b/patches/server/0798-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/0798-Fix-demo-flag-not-enabling-demo-mode.patch b/patches/server/0798-Fix-demo-flag-not-enabling-demo-mode.patch deleted file mode 100644 index db1ba5d6f6..0000000000 --- a/patches/server/0798-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 16322471d83c461098a6ada11e790b9fba7b5ea2..731bdabd53fd4a3d17494f26781223097a5d6e16 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -327,7 +327,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/0799-Add-Mob-Experience-reward-API.patch b/patches/server/0799-Add-Mob-Experience-reward-API.patch deleted file mode 100644 index 9e59c458f8..0000000000 --- a/patches/server/0799-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/0799-Break-redstone-on-top-of-trap-doors-early.patch b/patches/server/0799-Break-redstone-on-top-of-trap-doors-early.patch new file mode 100644 index 0000000000..ded460b32b --- /dev/null +++ b/patches/server/0799-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/0800-Avoid-Lazy-Initialization-for-Enum-Fields.patch b/patches/server/0800-Avoid-Lazy-Initialization-for-Enum-Fields.patch new file mode 100644 index 0000000000..becde16ce8 --- /dev/null +++ b/patches/server/0800-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/0800-Break-redstone-on-top-of-trap-doors-early.patch b/patches/server/0800-Break-redstone-on-top-of-trap-doors-early.patch deleted file mode 100644 index ded460b32b..0000000000 --- a/patches/server/0800-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/0801-Avoid-Lazy-Initialization-for-Enum-Fields.patch b/patches/server/0801-Avoid-Lazy-Initialization-for-Enum-Fields.patch deleted file mode 100644 index becde16ce8..0000000000 --- a/patches/server/0801-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/0801-More-accurate-isInOpenWater-impl.patch b/patches/server/0801-More-accurate-isInOpenWater-impl.patch new file mode 100644 index 0000000000..6e110094dd --- /dev/null +++ b/patches/server/0801-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/0802-Expand-PlayerItemMendEvent.patch b/patches/server/0802-Expand-PlayerItemMendEvent.patch new file mode 100644 index 0000000000..2bab45aff4 --- /dev/null +++ b/patches/server/0802-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 42e8dc24e5cb7b02639d4b80f831b8856f0f45d5..23b47d90fd35659d9eaa661e808a7f89b29614cf 100644 +--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java ++++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java +@@ -360,7 +360,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; +@@ -369,7 +372,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 809b1ead09246281fc09d5cbdaa2ad4432e13978..0dda38dcd777243779e74a34f171d0d3753025bb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1865,11 +1865,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 ec5c16f64d4e797b4c09bd0d3ae6f143d8795612..8fba20a2ff4ef43aa3bda1116f58b696bde2b9b8 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/0802-More-accurate-isInOpenWater-impl.patch b/patches/server/0802-More-accurate-isInOpenWater-impl.patch deleted file mode 100644 index 6e110094dd..0000000000 --- a/patches/server/0802-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/0803-Expand-PlayerItemMendEvent.patch b/patches/server/0803-Expand-PlayerItemMendEvent.patch deleted file mode 100644 index 2bab45aff4..0000000000 --- a/patches/server/0803-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 42e8dc24e5cb7b02639d4b80f831b8856f0f45d5..23b47d90fd35659d9eaa661e808a7f89b29614cf 100644 ---- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -@@ -360,7 +360,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; -@@ -369,7 +372,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 809b1ead09246281fc09d5cbdaa2ad4432e13978..0dda38dcd777243779e74a34f171d0d3753025bb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1865,11 +1865,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 ec5c16f64d4e797b4c09bd0d3ae6f143d8795612..8fba20a2ff4ef43aa3bda1116f58b696bde2b9b8 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/0803-Refresh-ProjectileSource-for-projectiles.patch b/patches/server/0803-Refresh-ProjectileSource-for-projectiles.patch new file mode 100644 index 0000000000..e5f111d2bb --- /dev/null +++ b/patches/server/0803-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 7897bec4aa04c93793af819cfaf8a7a751c4f1e4..777b6a5d63138c9332c1d32f1df6d0cc2e3b2844 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -394,6 +394,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 92bf8a3bac1146ed2393faa0f31e219288b466ca..c1b39e6fda0b2003e5e28ef94d13546497cbb79f 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/0804-Add-transient-modifier-API.patch b/patches/server/0804-Add-transient-modifier-API.patch new file mode 100644 index 0000000000..36cc0a030a --- /dev/null +++ b/patches/server/0804-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/0804-Refresh-ProjectileSource-for-projectiles.patch b/patches/server/0804-Refresh-ProjectileSource-for-projectiles.patch deleted file mode 100644 index 4d8e3cc45f..0000000000 --- a/patches/server/0804-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 5b2341e07d66feb4a3975eb2eb6208306c3ebaa9..29804084c93af884aea92d25b05e9bf20b92b620 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -394,6 +394,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 92bf8a3bac1146ed2393faa0f31e219288b466ca..c1b39e6fda0b2003e5e28ef94d13546497cbb79f 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/0805-Add-transient-modifier-API.patch b/patches/server/0805-Add-transient-modifier-API.patch deleted file mode 100644 index 36cc0a030a..0000000000 --- a/patches/server/0805-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/0805-Fix-block-place-logic.patch b/patches/server/0805-Fix-block-place-logic.patch new file mode 100644 index 0000000000..09a934ba3e --- /dev/null +++ b/patches/server/0805-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 cdd41eb371b1dd244a72c863cc5c8c4e84a9a71a..560932675223ea3ff75b6bf42b47ea5882ff953a 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 447e4c77b5cd90e744e014b66af5f0a9ebe9c2d8..c6133407f515f53c9fa67b988d4758d8f3d89f23 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -551,17 +551,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/0806-Fix-block-place-logic.patch b/patches/server/0806-Fix-block-place-logic.patch deleted file mode 100644 index 09a934ba3e..0000000000 --- a/patches/server/0806-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 cdd41eb371b1dd244a72c863cc5c8c4e84a9a71a..560932675223ea3ff75b6bf42b47ea5882ff953a 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 447e4c77b5cd90e744e014b66af5f0a9ebe9c2d8..c6133407f515f53c9fa67b988d4758d8f3d89f23 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -551,17 +551,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/0806-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch b/patches/server/0806-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch new file mode 100644 index 0000000000..41d0f0984e --- /dev/null +++ b/patches/server/0806-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 63872104e7302dbbc9c482a4ed8a9a34710e1eb4..18c4396219b4777e6d728a4d49727d0266709ccd 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -582,7 +582,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/0807-Call-BlockGrowEvent-for-missing-blocks.patch b/patches/server/0807-Call-BlockGrowEvent-for-missing-blocks.patch new file mode 100644 index 0000000000..d48638c261 --- /dev/null +++ b/patches/server/0807-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/0807-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch b/patches/server/0807-Fix-spigot-sound-playing-for-BlockItem-ItemStacks.patch deleted file mode 100644 index 41d0f0984e..0000000000 --- a/patches/server/0807-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 63872104e7302dbbc9c482a4ed8a9a34710e1eb4..18c4396219b4777e6d728a4d49727d0266709ccd 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -582,7 +582,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/0808-Call-BlockGrowEvent-for-missing-blocks.patch b/patches/server/0808-Call-BlockGrowEvent-for-missing-blocks.patch deleted file mode 100644 index d48638c261..0000000000 --- a/patches/server/0808-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/0808-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch b/patches/server/0808-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch new file mode 100644 index 0000000000..516bf15511 --- /dev/null +++ b/patches/server/0808-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 927846bf3281771de0274216abe927e524df3493..5c907eca23d936ba3095f2d81256775edaa737da 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/0809-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch b/patches/server/0809-Don-t-enforce-icanhasbukkit-default-if-alias-block-e.patch deleted file mode 100644 index 516bf15511..0000000000 --- a/patches/server/0809-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 927846bf3281771de0274216abe927e524df3493..5c907eca23d936ba3095f2d81256775edaa737da 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/0809-fix-MapLike-spam-for-missing-key-selector.patch b/patches/server/0809-fix-MapLike-spam-for-missing-key-selector.patch new file mode 100644 index 0000000000..2bd3b889f1 --- /dev/null +++ b/patches/server/0809-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/0810-Fix-sniffer-removeExploredLocation.patch b/patches/server/0810-Fix-sniffer-removeExploredLocation.patch new file mode 100644 index 0000000000..e8b1703090 --- /dev/null +++ b/patches/server/0810-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/0810-fix-MapLike-spam-for-missing-key-selector.patch b/patches/server/0810-fix-MapLike-spam-for-missing-key-selector.patch deleted file mode 100644 index 2bd3b889f1..0000000000 --- a/patches/server/0810-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/0811-Add-method-to-remove-all-active-potion-effects.patch b/patches/server/0811-Add-method-to-remove-all-active-potion-effects.patch new file mode 100644 index 0000000000..21ed7d09a9 --- /dev/null +++ b/patches/server/0811-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 cf388e227cd5893619ab5d05fee4a43c00ba0d9a..cbcd3563d1fda1038f9113da6ff88db9507a0f02 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/0811-Fix-sniffer-removeExploredLocation.patch b/patches/server/0811-Fix-sniffer-removeExploredLocation.patch deleted file mode 100644 index e8b1703090..0000000000 --- a/patches/server/0811-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/0812-Add-event-for-player-editing-sign.patch b/patches/server/0812-Add-event-for-player-editing-sign.patch new file mode 100644 index 0000000000..9affd7f9eb --- /dev/null +++ b/patches/server/0812-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 18c4396219b4777e6d728a4d49727d0266709ccd..938e21425bf33a98f727d428216067ee0631c4bf 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -561,7 +561,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/0812-Add-method-to-remove-all-active-potion-effects.patch b/patches/server/0812-Add-method-to-remove-all-active-potion-effects.patch deleted file mode 100644 index 21ed7d09a9..0000000000 --- a/patches/server/0812-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 cf388e227cd5893619ab5d05fee4a43c00ba0d9a..cbcd3563d1fda1038f9113da6ff88db9507a0f02 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/0813-Add-event-for-player-editing-sign.patch b/patches/server/0813-Add-event-for-player-editing-sign.patch deleted file mode 100644 index 9affd7f9eb..0000000000 --- a/patches/server/0813-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 18c4396219b4777e6d728a4d49727d0266709ccd..938e21425bf33a98f727d428216067ee0631c4bf 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -561,7 +561,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/0813-Only-tick-item-frames-if-players-can-see-it.patch b/patches/server/0813-Only-tick-item-frames-if-players-can-see-it.patch new file mode 100644 index 0000000000..79607ddfe1 --- /dev/null +++ b/patches/server/0813-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 78d3aa089d990190cdf5cd7ac14410909235f133..436eb27ddc6a36b8bbf46efd9532c4e371024a98 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/0814-Fix-cmd-permission-levels-for-command-blocks.patch b/patches/server/0814-Fix-cmd-permission-levels-for-command-blocks.patch new file mode 100644 index 0000000000..ef8302664b --- /dev/null +++ b/patches/server/0814-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 977f9ac300490562d9894af4a42621b594f0a8e0..cfa328f06c1b972c8328ff40580b485c02e0c270 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 8e741e7c3ed5a181b0999650a94dbf86b10a75ca..a811cdca34bb468ac355f72decd153d4f0618009 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java +@@ -128,7 +128,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 126c16808336fbef82c681b822a921a62ce46e7c..e2123f1c5852a34fb92e900f25591284625f3494 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/0814-Only-tick-item-frames-if-players-can-see-it.patch b/patches/server/0814-Only-tick-item-frames-if-players-can-see-it.patch deleted file mode 100644 index 79607ddfe1..0000000000 --- a/patches/server/0814-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 78d3aa089d990190cdf5cd7ac14410909235f133..436eb27ddc6a36b8bbf46efd9532c4e371024a98 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/0815-Add-option-to-disable-block-updates.patch b/patches/server/0815-Add-option-to-disable-block-updates.patch new file mode 100644 index 0000000000..0ea835ecc9 --- /dev/null +++ b/patches/server/0815-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/0815-Fix-cmd-permission-levels-for-command-blocks.patch b/patches/server/0815-Fix-cmd-permission-levels-for-command-blocks.patch deleted file mode 100644 index ef8302664b..0000000000 --- a/patches/server/0815-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 977f9ac300490562d9894af4a42621b594f0a8e0..cfa328f06c1b972c8328ff40580b485c02e0c270 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 8e741e7c3ed5a181b0999650a94dbf86b10a75ca..a811cdca34bb468ac355f72decd153d4f0618009 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java -@@ -128,7 +128,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 126c16808336fbef82c681b822a921a62ce46e7c..e2123f1c5852a34fb92e900f25591284625f3494 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/0816-Add-option-to-disable-block-updates.patch b/patches/server/0816-Add-option-to-disable-block-updates.patch deleted file mode 100644 index 0ea835ecc9..0000000000 --- a/patches/server/0816-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/0816-Call-missing-BlockDispenseEvent.patch b/patches/server/0816-Call-missing-BlockDispenseEvent.patch new file mode 100644 index 0000000000..b0cd223356 --- /dev/null +++ b/patches/server/0816-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 780f83d50aac70c819608f4c79c08ef34664d7b0..8322b54451a6203a8969fdc96ed63bbcc0dd2f5a 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 8fba20a2ff4ef43aa3bda1116f58b696bde2b9b8..28e56095ec4b6fb73df747ec796498f8692c2a24 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/0817-Call-missing-BlockDispenseEvent.patch b/patches/server/0817-Call-missing-BlockDispenseEvent.patch deleted file mode 100644 index b0cd223356..0000000000 --- a/patches/server/0817-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 780f83d50aac70c819608f4c79c08ef34664d7b0..8322b54451a6203a8969fdc96ed63bbcc0dd2f5a 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 8fba20a2ff4ef43aa3bda1116f58b696bde2b9b8..28e56095ec4b6fb73df747ec796498f8692c2a24 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/0817-Don-t-load-chunks-for-supporting-block-checks.patch b/patches/server/0817-Don-t-load-chunks-for-supporting-block-checks.patch new file mode 100644 index 0000000000..306f756bb9 --- /dev/null +++ b/patches/server/0817-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 777b6a5d63138c9332c1d32f1df6d0cc2e3b2844..f2c36ab6d4124bee1ce4c534481117d655343a10 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -1242,7 +1242,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/0818-Don-t-load-chunks-for-supporting-block-checks.patch b/patches/server/0818-Don-t-load-chunks-for-supporting-block-checks.patch deleted file mode 100644 index c00de60113..0000000000 --- a/patches/server/0818-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 29804084c93af884aea92d25b05e9bf20b92b620..d3457d9576dcacb0adbcc1884a407d5b24680563 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1242,7 +1242,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/0818-Optimize-player-lookups-for-beacons.patch b/patches/server/0818-Optimize-player-lookups-for-beacons.patch new file mode 100644 index 0000000000..7e1285d891 --- /dev/null +++ b/patches/server/0818-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/0819-More-Sign-Block-API.patch b/patches/server/0819-More-Sign-Block-API.patch new file mode 100644 index 0000000000..41c9eb5851 --- /dev/null +++ b/patches/server/0819-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 86550d200922ee313019a21fe593c594c967f28b..7a1d9a718dc57b5f630ca8e5358120cebaeefb9c 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/0819-Optimize-player-lookups-for-beacons.patch b/patches/server/0819-Optimize-player-lookups-for-beacons.patch deleted file mode 100644 index 7e1285d891..0000000000 --- a/patches/server/0819-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/0820-More-Sign-Block-API.patch b/patches/server/0820-More-Sign-Block-API.patch deleted file mode 100644 index 41c9eb5851..0000000000 --- a/patches/server/0820-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 86550d200922ee313019a21fe593c594c967f28b..7a1d9a718dc57b5f630ca8e5358120cebaeefb9c 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/0820-fix-item-meta-for-tadpole-buckets.patch b/patches/server/0820-fix-item-meta-for-tadpole-buckets.patch new file mode 100644 index 0000000000..0ad43795a2 --- /dev/null +++ b/patches/server/0820-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 6cc54035af870b75f45d836e5b60f5d9240dd7d0..c27f37fd8a0e90b1440bfd4329d044eb8df629d2 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/0821-Fix-BanList-API.patch b/patches/server/0821-Fix-BanList-API.patch new file mode 100644 index 0000000000..7cf35da66c --- /dev/null +++ b/patches/server/0821-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 0dda38dcd777243779e74a34f171d0d3753025bb..d47b44adb0989c5540343d8f71095e73d49c8190 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1759,23 +1759,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); + } +@@ -1783,12 +1783,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/0821-fix-item-meta-for-tadpole-buckets.patch b/patches/server/0821-fix-item-meta-for-tadpole-buckets.patch deleted file mode 100644 index 0ad43795a2..0000000000 --- a/patches/server/0821-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 6cc54035af870b75f45d836e5b60f5d9240dd7d0..c27f37fd8a0e90b1440bfd4329d044eb8df629d2 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/0822-Determine-lava-and-water-fluid-explosion-resistance-.patch b/patches/server/0822-Determine-lava-and-water-fluid-explosion-resistance-.patch new file mode 100644 index 0000000000..4f2b8e09cd --- /dev/null +++ b/patches/server/0822-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/0822-Fix-BanList-API.patch b/patches/server/0822-Fix-BanList-API.patch deleted file mode 100644 index 7cf35da66c..0000000000 --- a/patches/server/0822-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 0dda38dcd777243779e74a34f171d0d3753025bb..d47b44adb0989c5540343d8f71095e73d49c8190 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1759,23 +1759,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); - } -@@ -1783,12 +1783,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/0823-Determine-lava-and-water-fluid-explosion-resistance-.patch b/patches/server/0823-Determine-lava-and-water-fluid-explosion-resistance-.patch deleted file mode 100644 index 4f2b8e09cd..0000000000 --- a/patches/server/0823-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/0823-Fix-possible-NPE-on-painting-creation.patch b/patches/server/0823-Fix-possible-NPE-on-painting-creation.patch new file mode 100644 index 0000000000..814434abed --- /dev/null +++ b/patches/server/0823-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 2a32f2aa3cb7395900cf2d06cc2dcd4ddacd4145..007d870b3f1dbf0ffa3a2d9af3c49d3f3eea54d7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -359,8 +359,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()); +@@ -527,6 +532,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/0824-Fix-possible-NPE-on-painting-creation.patch b/patches/server/0824-Fix-possible-NPE-on-painting-creation.patch deleted file mode 100644 index 814434abed..0000000000 --- a/patches/server/0824-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 2a32f2aa3cb7395900cf2d06cc2dcd4ddacd4145..007d870b3f1dbf0ffa3a2d9af3c49d3f3eea54d7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -359,8 +359,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()); -@@ -527,6 +532,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/0824-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch b/patches/server/0824-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch new file mode 100644 index 0000000000..c481798890 --- /dev/null +++ b/patches/server/0824-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/0825-ExperienceOrb-should-call-EntitySpawnEvent.patch b/patches/server/0825-ExperienceOrb-should-call-EntitySpawnEvent.patch new file mode 100644 index 0000000000..da24259a50 --- /dev/null +++ b/patches/server/0825-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 28e56095ec4b6fb73df747ec796498f8692c2a24..b1ce440bc5c8b77654213a4630851daef3f15d60 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/0825-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch b/patches/server/0825-Only-set-despawnTimer-for-Wandering-Traders-spawned-.patch deleted file mode 100644 index c481798890..0000000000 --- a/patches/server/0825-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/0826-ExperienceOrb-should-call-EntitySpawnEvent.patch b/patches/server/0826-ExperienceOrb-should-call-EntitySpawnEvent.patch deleted file mode 100644 index da24259a50..0000000000 --- a/patches/server/0826-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 28e56095ec4b6fb73df747ec796498f8692c2a24..b1ce440bc5c8b77654213a4630851daef3f15d60 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/0826-Make-Amethyst-throw-both-Spread-and-Grow-Events.patch b/patches/server/0826-Make-Amethyst-throw-both-Spread-and-Grow-Events.patch new file mode 100644 index 0000000000..301b345fb9 --- /dev/null +++ b/patches/server/0826-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/0827-Add-whitelist-events.patch b/patches/server/0827-Add-whitelist-events.patch new file mode 100644 index 0000000000..96884032fb --- /dev/null +++ b/patches/server/0827-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/0828-Add-whitelist-events.patch b/patches/server/0828-Add-whitelist-events.patch deleted file mode 100644 index 96884032fb..0000000000 --- a/patches/server/0828-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 13b71e5572f68f5992bc95638c11a4f6a8e18099..ed68a02dc3f3265b3a2c911767186a1268ea7212 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -1325,8 +1325,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); +@@ -1393,8 +1393,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 + +@@ -1403,9 +1409,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 + } + } + } +@@ -1467,14 +1480,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 { +@@ -3588,4 +3618,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/0829-Folia-scheduler-and-owned-region-API.patch b/patches/server/0829-Folia-scheduler-and-owned-region-API.patch new file mode 100644 index 0000000000..fe801d1588 --- /dev/null +++ b/patches/server/0829-Folia-scheduler-and-owned-region-API.patch @@ -0,0 +1,1376 @@ +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 0c44f59445e9cd5d2767cbabe874e137b2420a2d..4555f7f59d15a1f84c0cf76f77a6685fadd48f8c 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1624,6 +1624,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 28ca991e89fc0c651220c65cb939f9ebb12d9c93..8b54fab09699dec0cb0fb6063accb04e48a36b6e 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 f2c36ab6d4124bee1ce4c534481117d655343a10..86f3955f938a512d1cc3207862549f4a6e6e67c8 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -263,10 +263,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() { +@@ -4736,6 +4747,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; + } +@@ -4747,12 +4759,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 5c907eca23d936ba3095f2d81256775edaa737da..4c4fa7bbafb075beb0d9c1ef21e3ba2d62b1ae65 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -313,6 +313,88 @@ 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(World world, int minChunkX, int minChunkZ, int maxChunkX, int maxChunkZ) { ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( ++ ((CraftWorld) world).getHandle(), minChunkX, minChunkZ, maxChunkX, maxChunkZ ++ ); ++ } ++ ++ @Override ++ public final boolean isOwnedByCurrentRegion(Entity entity) { ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandleRaw()); ++ } ++ ++ @Override ++ public final boolean isGlobalTickThread() { ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThread(); ++ } ++ // 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 f1992713a9e61a9e3cd719d4676f4c3f2917435d..d078f21456ce3fb68d4a08614aa912f08728f85b 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/0829-Implement-PlayerFailMoveEvent.patch b/patches/server/0829-Implement-PlayerFailMoveEvent.patch deleted file mode 100644 index bc287c4f27..0000000000 --- a/patches/server/0829-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 13b71e5572f68f5992bc95638c11a4f6a8e18099..ed68a02dc3f3265b3a2c911767186a1268ea7212 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1325,8 +1325,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); -@@ -1393,8 +1393,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 - -@@ -1403,9 +1409,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 - } - } - } -@@ -1467,14 +1480,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 { -@@ -3588,4 +3618,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/0830-Folia-scheduler-and-owned-region-API.patch b/patches/server/0830-Folia-scheduler-and-owned-region-API.patch deleted file mode 100644 index cf424af53f..0000000000 --- a/patches/server/0830-Folia-scheduler-and-owned-region-API.patch +++ /dev/null @@ -1,1376 +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 0c44f59445e9cd5d2767cbabe874e137b2420a2d..4555f7f59d15a1f84c0cf76f77a6685fadd48f8c 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1624,6 +1624,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 28ca991e89fc0c651220c65cb939f9ebb12d9c93..8b54fab09699dec0cb0fb6063accb04e48a36b6e 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 d3457d9576dcacb0adbcc1884a407d5b24680563..c7292ddae2a2cb11434a6962706bc2a8dd5d2cdc 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -263,10 +263,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() { -@@ -4736,6 +4747,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; - } -@@ -4747,12 +4759,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 5c907eca23d936ba3095f2d81256775edaa737da..4c4fa7bbafb075beb0d9c1ef21e3ba2d62b1ae65 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -313,6 +313,88 @@ 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(World world, int minChunkX, int minChunkZ, int maxChunkX, int maxChunkZ) { -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor( -+ ((CraftWorld) world).getHandle(), minChunkX, minChunkZ, maxChunkX, maxChunkZ -+ ); -+ } -+ -+ @Override -+ public final boolean isOwnedByCurrentRegion(Entity entity) { -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandleRaw()); -+ } -+ -+ @Override -+ public final boolean isGlobalTickThread() { -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThread(); -+ } -+ // 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 f1992713a9e61a9e3cd719d4676f4c3f2917435d..d078f21456ce3fb68d4a08614aa912f08728f85b 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/0830-Only-erase-allay-memory-on-non-item-targets.patch b/patches/server/0830-Only-erase-allay-memory-on-non-item-targets.patch new file mode 100644 index 0000000000..6342f7dee7 --- /dev/null +++ b/patches/server/0830-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 lose 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/0831-Fix-rotation-when-spawning-display-entities.patch b/patches/server/0831-Fix-rotation-when-spawning-display-entities.patch new file mode 100644 index 0000000000..3cc44c57fa --- /dev/null +++ b/patches/server/0831-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 007d870b3f1dbf0ffa3a2d9af3c49d3f3eea54d7..7331a8e22aa80534b60bbbedd9b9c3f4455e0de7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -253,6 +253,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<>(); + +@@ -413,10 +414,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/0831-Only-erase-allay-memory-on-non-item-targets.patch b/patches/server/0831-Only-erase-allay-memory-on-non-item-targets.patch deleted file mode 100644 index 6342f7dee7..0000000000 --- a/patches/server/0831-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 lose 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/0832-Fix-rotation-when-spawning-display-entities.patch b/patches/server/0832-Fix-rotation-when-spawning-display-entities.patch deleted file mode 100644 index 3cc44c57fa..0000000000 --- a/patches/server/0832-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 007d870b3f1dbf0ffa3a2d9af3c49d3f3eea54d7..7331a8e22aa80534b60bbbedd9b9c3f4455e0de7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -253,6 +253,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<>(); - -@@ -413,10 +414,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/0832-Only-capture-actual-tree-growth.patch b/patches/server/0832-Only-capture-actual-tree-growth.patch new file mode 100644 index 0000000000..738f88f33b --- /dev/null +++ b/patches/server/0832-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 8322b54451a6203a8969fdc96ed63bbcc0dd2f5a..5414f05a7a2d9858785d68446f03f2b854799687 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 1242ddeb98c5a0582591a071ef615f726f6aa132..9b4e3144b062007b936b3b444320646061cc0133 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -2213,6 +2213,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 938e21425bf33a98f727d428216067ee0631c4bf..30ba2750e884ceff89e87e2155f18ea66a05ee36 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -474,6 +474,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/0833-Only-capture-actual-tree-growth.patch b/patches/server/0833-Only-capture-actual-tree-growth.patch deleted file mode 100644 index 738f88f33b..0000000000 --- a/patches/server/0833-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 8322b54451a6203a8969fdc96ed63bbcc0dd2f5a..5414f05a7a2d9858785d68446f03f2b854799687 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 1242ddeb98c5a0582591a071ef615f726f6aa132..9b4e3144b062007b936b3b444320646061cc0133 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2213,6 +2213,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 938e21425bf33a98f727d428216067ee0631c4bf..30ba2750e884ceff89e87e2155f18ea66a05ee36 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -474,6 +474,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/0833-Use-correct-source-for-mushroom-block-spread-event.patch b/patches/server/0833-Use-correct-source-for-mushroom-block-spread-event.patch new file mode 100644 index 0000000000..658d9ec376 --- /dev/null +++ b/patches/server/0833-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/0834-Respect-randomizeData-on-more-entities-when-spawning.patch b/patches/server/0834-Respect-randomizeData-on-more-entities-when-spawning.patch new file mode 100644 index 0000000000..eb12d81d79 --- /dev/null +++ b/patches/server/0834-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 7331a8e22aa80534b60bbbedd9b9c3f4455e0de7..f423bcee46506eccbaf61090adb886a31714c04d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +@@ -254,6 +254,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<>(); + +@@ -426,11 +433,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)))); +@@ -441,12 +449,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/0834-Use-correct-source-for-mushroom-block-spread-event.patch b/patches/server/0834-Use-correct-source-for-mushroom-block-spread-event.patch deleted file mode 100644 index 658d9ec376..0000000000 --- a/patches/server/0834-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/0835-Respect-randomizeData-on-more-entities-when-spawning.patch b/patches/server/0835-Respect-randomizeData-on-more-entities-when-spawning.patch deleted file mode 100644 index eb12d81d79..0000000000 --- a/patches/server/0835-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 7331a8e22aa80534b60bbbedd9b9c3f4455e0de7..f423bcee46506eccbaf61090adb886a31714c04d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java -@@ -254,6 +254,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<>(); - -@@ -426,11 +433,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)))); -@@ -441,12 +449,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/0835-Use-correct-seed-on-api-world-load.patch b/patches/server/0835-Use-correct-seed-on-api-world-load.patch new file mode 100644 index 0000000000..80e41be4af --- /dev/null +++ b/patches/server/0835-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 4c4fa7bbafb075beb0d9c1ef21e3ba2d62b1ae65..54b5dee7cfd19ad58e376eee80d3827f1a80cfcd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1400,7 +1400,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/0836-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch b/patches/server/0836-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch new file mode 100644 index 0000000000..d87f310ded --- /dev/null +++ b/patches/server/0836-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/0836-Use-correct-seed-on-api-world-load.patch b/patches/server/0836-Use-correct-seed-on-api-world-load.patch deleted file mode 100644 index 80e41be4af..0000000000 --- a/patches/server/0836-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 4c4fa7bbafb075beb0d9c1ef21e3ba2d62b1ae65..54b5dee7cfd19ad58e376eee80d3827f1a80cfcd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1400,7 +1400,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/0837-Cache-map-ids-on-item-frames.patch b/patches/server/0837-Cache-map-ids-on-item-frames.patch new file mode 100644 index 0000000000..50c1186a78 --- /dev/null +++ b/patches/server/0837-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 436eb27ddc6a36b8bbf46efd9532c4e371024a98..12d5af9dc6e5d5ed4ea427384226dc5d022550ba 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 3ef9be2b076160783adce2f1d74b3118544e66da..7d83ad8a61f6aafbc063506c1858554f9b700b70 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/0837-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch b/patches/server/0837-Remove-UpgradeData-neighbour-ticks-outside-of-range.patch deleted file mode 100644 index d87f310ded..0000000000 --- a/patches/server/0837-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/0838-API-for-updating-recipes-on-clients.patch b/patches/server/0838-API-for-updating-recipes-on-clients.patch new file mode 100644 index 0000000000..77a9a4fe09 --- /dev/null +++ b/patches/server/0838-API-for-updating-recipes-on-clients.patch @@ -0,0 +1,113 @@ +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 8b54fab09699dec0cb0fb6063accb04e48a36b6e..bd097ae6edfc0ad810d41ed8bbc7fab34d255610 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -1449,6 +1449,13 @@ public abstract class PlayerList { + } + + public void reloadResources() { ++ // Paper start - API for updating recipes on clients ++ this.reloadAdvancementData(); ++ this.reloadTagData(); ++ this.reloadRecipes(); ++ } ++ public void reloadAdvancementData() { ++ // Paper end - API for updating recipes on clients + // CraftBukkit start + /*Iterator iterator = this.advancements.values().iterator(); + +@@ -1464,9 +1471,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))); + // CraftBukkit start +- this.reloadRecipes(); ++ // this.reloadRecipes(); // Paper - do not reload recipes just because tag data was reloaded ++ // Paper end - API for updating recipes on clients + } + + public void reloadRecipes() { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 54b5dee7cfd19ad58e376eee80d3827f1a80cfcd..a755137d8d4b266a648cb2a4f41a5ed00262f121 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1190,6 +1190,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.reloadRecipes(); ++ } ++ // Paper end - API for updating recipes on clients ++ + private void loadIcon() { + this.icon = new CraftIconCache(null); + try { +@@ -1569,6 +1581,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; +@@ -1600,6 +1619,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.reloadRecipes(); ++ } ++ // Paper end - API for updating recipes on clients + return true; + } + +@@ -1780,9 +1804,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.reloadRecipes(); ++ } ++ return removed; ++ // Paper end - resend recipes on successful removal + } + + @Override diff --git a/patches/server/0838-Cache-map-ids-on-item-frames.patch b/patches/server/0838-Cache-map-ids-on-item-frames.patch deleted file mode 100644 index 368e04a7a0..0000000000 --- a/patches/server/0838-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 436eb27ddc6a36b8bbf46efd9532c4e371024a98..12d5af9dc6e5d5ed4ea427384226dc5d022550ba 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 d431ee93cd7e87a24ff4079288facd089053d725..bbdaaa1cc0b4aed28bc39385508d221055b99d4d 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/0839-API-for-updating-recipes-on-clients.patch b/patches/server/0839-API-for-updating-recipes-on-clients.patch deleted file mode 100644 index 77a9a4fe09..0000000000 --- a/patches/server/0839-API-for-updating-recipes-on-clients.patch +++ /dev/null @@ -1,113 +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 8b54fab09699dec0cb0fb6063accb04e48a36b6e..bd097ae6edfc0ad810d41ed8bbc7fab34d255610 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1449,6 +1449,13 @@ public abstract class PlayerList { - } - - public void reloadResources() { -+ // Paper start - API for updating recipes on clients -+ this.reloadAdvancementData(); -+ this.reloadTagData(); -+ this.reloadRecipes(); -+ } -+ public void reloadAdvancementData() { -+ // Paper end - API for updating recipes on clients - // CraftBukkit start - /*Iterator iterator = this.advancements.values().iterator(); - -@@ -1464,9 +1471,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))); - // CraftBukkit start -- this.reloadRecipes(); -+ // this.reloadRecipes(); // Paper - do not reload recipes just because tag data was reloaded -+ // Paper end - API for updating recipes on clients - } - - public void reloadRecipes() { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 54b5dee7cfd19ad58e376eee80d3827f1a80cfcd..a755137d8d4b266a648cb2a4f41a5ed00262f121 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1190,6 +1190,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.reloadRecipes(); -+ } -+ // Paper end - API for updating recipes on clients -+ - private void loadIcon() { - this.icon = new CraftIconCache(null); - try { -@@ -1569,6 +1581,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; -@@ -1600,6 +1619,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.reloadRecipes(); -+ } -+ // Paper end - API for updating recipes on clients - return true; - } - -@@ -1780,9 +1804,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.reloadRecipes(); -+ } -+ return removed; -+ // Paper end - resend recipes on successful removal - } - - @Override diff --git a/patches/server/0839-Fix-custom-statistic-criteria-creation.patch b/patches/server/0839-Fix-custom-statistic-criteria-creation.patch new file mode 100644 index 0000000000..b601922015 --- /dev/null +++ b/patches/server/0839-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 088ff124ca82e69e59e02e6604959e399e4aff03..cd00165ebb193c788e05a6f0b2b649936d56aa9f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -608,6 +608,12 @@ public final class CraftMagicNumbers implements UnsafeValues { + public void setBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z, org.bukkit.NamespacedKey biomeKey) { + accessor.setBiome(x, y, z, org.bukkit.Registry.BIOME.getOrThrow(biomeKey)); + } ++ ++ @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/0840-Bandaid-fix-for-Effect.patch b/patches/server/0840-Bandaid-fix-for-Effect.patch new file mode 100644 index 0000000000..38971ab5b3 --- /dev/null +++ b/patches/server/0840-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 5379931b2403566f54e4ecf0699229d636d2d38f..231089eab86f5d3e33ddb6d5cb8358d5d5d5eaf4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1363,7 +1363,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 d47b44adb0989c5540343d8f71095e73d49c8190..1f188f80e4c8831ea4b585f7a4bf01009a480353 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -924,7 +924,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/0840-Fix-custom-statistic-criteria-creation.patch b/patches/server/0840-Fix-custom-statistic-criteria-creation.patch deleted file mode 100644 index b601922015..0000000000 --- a/patches/server/0840-Fix-custom-statistic-criteria-creation.patch +++ /dev/null @@ -1,23 +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 088ff124ca82e69e59e02e6604959e399e4aff03..cd00165ebb193c788e05a6f0b2b649936d56aa9f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -608,6 +608,12 @@ public final class CraftMagicNumbers implements UnsafeValues { - public void setBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z, org.bukkit.NamespacedKey biomeKey) { - accessor.setBiome(x, y, z, org.bukkit.Registry.BIOME.getOrThrow(biomeKey)); - } -+ -+ @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/0841-Bandaid-fix-for-Effect.patch b/patches/server/0841-Bandaid-fix-for-Effect.patch deleted file mode 100644 index 38971ab5b3..0000000000 --- a/patches/server/0841-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 5379931b2403566f54e4ecf0699229d636d2d38f..231089eab86f5d3e33ddb6d5cb8358d5d5d5eaf4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1363,7 +1363,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 d47b44adb0989c5540343d8f71095e73d49c8190..1f188f80e4c8831ea4b585f7a4bf01009a480353 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -924,7 +924,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/0841-SculkCatalyst-bloom-API.patch b/patches/server/0841-SculkCatalyst-bloom-API.patch new file mode 100644 index 0000000000..ba050f6086 --- /dev/null +++ b/patches/server/0841-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 d078f21456ce3fb68d4a08614aa912f08728f85b..0278cd156e3a82df4289f483967512dad63a0644 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1259,4 +1259,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/0842-SculkCatalyst-bloom-API.patch b/patches/server/0842-SculkCatalyst-bloom-API.patch deleted file mode 100644 index ba050f6086..0000000000 --- a/patches/server/0842-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 d078f21456ce3fb68d4a08614aa912f08728f85b..0278cd156e3a82df4289f483967512dad63a0644 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1259,4 +1259,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/0843-Deprecate-and-replace-methods-with-old-StructureType.patch b/patches/server/0843-Deprecate-and-replace-methods-with-old-StructureType.patch new file mode 100644 index 0000000000..d058ddea87 --- /dev/null +++ b/patches/server/0843-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 a755137d8d4b266a648cb2a4f41a5ed00262f121..eaea08530ca864158a2fa15dca38ca0c25a49bde 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2019,6 +2019,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 +@@ -2029,6 +2034,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/0844-Deprecate-and-replace-methods-with-old-StructureType.patch b/patches/server/0844-Deprecate-and-replace-methods-with-old-StructureType.patch deleted file mode 100644 index d058ddea87..0000000000 --- a/patches/server/0844-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 a755137d8d4b266a648cb2a4f41a5ed00262f121..eaea08530ca864158a2fa15dca38ca0c25a49bde 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2019,6 +2019,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 -@@ -2029,6 +2034,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/0844-Don-t-tab-complete-namespaced-commands-if-send-names.patch b/patches/server/0844-Don-t-tab-complete-namespaced-commands-if-send-names.patch new file mode 100644 index 0000000000..8c20d499c8 --- /dev/null +++ b/patches/server/0844-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 ed68a02dc3f3265b3a2c911767186a1268ea7212..a2c404e4cd808a3a676ae3808852e4105bdc9af4 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -830,6 +830,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/0845-Don-t-tab-complete-namespaced-commands-if-send-names.patch b/patches/server/0845-Don-t-tab-complete-namespaced-commands-if-send-names.patch deleted file mode 100644 index 8c20d499c8..0000000000 --- a/patches/server/0845-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 ed68a02dc3f3265b3a2c911767186a1268ea7212..a2c404e4cd808a3a676ae3808852e4105bdc9af4 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -830,6 +830,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/0845-Properly-handle-BlockBreakEvent-isDropItems.patch b/patches/server/0845-Properly-handle-BlockBreakEvent-isDropItems.patch new file mode 100644 index 0000000000..3dbf3d2344 --- /dev/null +++ b/patches/server/0845-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 3e3951cbb196b720256cfc36d6d3b91d48ce3294..4e709c9b126c905a98156639c5ab193a5c496793 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 3c7e373eb1601670d923e6ffa46817ca53e321db..0189ff670d84df375399c492467fd4d5c62eff09 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/0846-Fire-entity-death-event-for-ender-dragon.patch b/patches/server/0846-Fire-entity-death-event-for-ender-dragon.patch new file mode 100644 index 0000000000..f3f16c5e4c --- /dev/null +++ b/patches/server/0846-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 037b261a40a800f6d5e9ecd22e230d030b797958..d5fc74dbc2c5f6b65fee46e7797b151144c8fd41 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/0846-Properly-handle-BlockBreakEvent-isDropItems.patch b/patches/server/0846-Properly-handle-BlockBreakEvent-isDropItems.patch deleted file mode 100644 index 3dbf3d2344..0000000000 --- a/patches/server/0846-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 3e3951cbb196b720256cfc36d6d3b91d48ce3294..4e709c9b126c905a98156639c5ab193a5c496793 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 3c7e373eb1601670d923e6ffa46817ca53e321db..0189ff670d84df375399c492467fd4d5c62eff09 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/0847-Configurable-entity-tracking-range-by-Y-coordinate.patch b/patches/server/0847-Configurable-entity-tracking-range-by-Y-coordinate.patch new file mode 100644 index 0000000000..b838446e28 --- /dev/null +++ b/patches/server/0847-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 c1c2eeba0f5b8e499cc51cc1df7bf9acb61bd7d6..054c962288585ef3d0249d68c24d85624f172374 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1571,7 +1571,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/0847-Fire-entity-death-event-for-ender-dragon.patch b/patches/server/0847-Fire-entity-death-event-for-ender-dragon.patch deleted file mode 100644 index f3f16c5e4c..0000000000 --- a/patches/server/0847-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 037b261a40a800f6d5e9ecd22e230d030b797958..d5fc74dbc2c5f6b65fee46e7797b151144c8fd41 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/0848-Add-Listing-API-for-Player.patch b/patches/server/0848-Add-Listing-API-for-Player.patch new file mode 100644 index 0000000000..b23b4a4362 --- /dev/null +++ b/patches/server/0848-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 6bfb83434a184e6fdba932f692281f0303ada65f..e2541a3886504b143f858a4e75ac4746d4d39e28 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java +@@ -38,6 +38,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( +@@ -53,6 +64,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 -> { +@@ -165,10 +198,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 1f188f80e4c8831ea4b585f7a4bf01009a480353..006d44e0a1175980f80f6cac0b0f7ed3eef47a52 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; +@@ -2104,7 +2105,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 + } + +@@ -2208,6 +2209,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/0848-Configurable-entity-tracking-range-by-Y-coordinate.patch b/patches/server/0848-Configurable-entity-tracking-range-by-Y-coordinate.patch deleted file mode 100644 index b838446e28..0000000000 --- a/patches/server/0848-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 c1c2eeba0f5b8e499cc51cc1df7bf9acb61bd7d6..054c962288585ef3d0249d68c24d85624f172374 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1571,7 +1571,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/0849-Add-Listing-API-for-Player.patch b/patches/server/0849-Add-Listing-API-for-Player.patch deleted file mode 100644 index b23b4a4362..0000000000 --- a/patches/server/0849-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 6bfb83434a184e6fdba932f692281f0303ada65f..e2541a3886504b143f858a4e75ac4746d4d39e28 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java -@@ -38,6 +38,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( -@@ -53,6 +64,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 -> { -@@ -165,10 +198,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 1f188f80e4c8831ea4b585f7a4bf01009a480353..006d44e0a1175980f80f6cac0b0f7ed3eef47a52 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; -@@ -2104,7 +2105,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 - } - -@@ -2208,6 +2209,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/0849-Configurable-Region-Compression-Format.patch b/patches/server/0849-Configurable-Region-Compression-Format.patch new file mode 100644 index 0000000000..ce17b1e202 --- /dev/null +++ b/patches/server/0849-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 b24e8255ab18eb5b2e4968aa62aa3d72ef33f0eb..0028f4fd331b6f94be2a2b4d90e56dcdd881178d 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/0850-Add-BlockFace-to-BlockDamageEvent.patch b/patches/server/0850-Add-BlockFace-to-BlockDamageEvent.patch new file mode 100644 index 0000000000..a5b150b6fc --- /dev/null +++ b/patches/server/0850-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 b1ce440bc5c8b77654213a4630851daef3f15d60..8853f0cfebfe56fd2aa3ec975701b5ffaad46257 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/0850-Configurable-Region-Compression-Format.patch b/patches/server/0850-Configurable-Region-Compression-Format.patch deleted file mode 100644 index ce17b1e202..0000000000 --- a/patches/server/0850-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 b24e8255ab18eb5b2e4968aa62aa3d72ef33f0eb..0028f4fd331b6f94be2a2b4d90e56dcdd881178d 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/0851-Add-BlockFace-to-BlockDamageEvent.patch b/patches/server/0851-Add-BlockFace-to-BlockDamageEvent.patch deleted file mode 100644 index a5b150b6fc..0000000000 --- a/patches/server/0851-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 b1ce440bc5c8b77654213a4630851daef3f15d60..8853f0cfebfe56fd2aa3ec975701b5ffaad46257 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/0851-Fix-NPE-on-Boat-getStatus.patch b/patches/server/0851-Fix-NPE-on-Boat-getStatus.patch new file mode 100644 index 0000000000..19f832054d --- /dev/null +++ b/patches/server/0851-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/0852-Expand-Pose-API.patch b/patches/server/0852-Expand-Pose-API.patch new file mode 100644 index 0000000000..dbb1f034ea --- /dev/null +++ b/patches/server/0852-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 86f3955f938a512d1cc3207862549f4a6e6e67c8..96c252a797a971f36ccaf83ee00da27cf38a2f6c 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -428,6 +428,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(); +@@ -626,6 +627,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 0278cd156e3a82df4289f483967512dad63a0644..4c3029a6e4b50afc945797ab23e8c67acba70345 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -895,6 +895,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/0852-Fix-NPE-on-Boat-getStatus.patch b/patches/server/0852-Fix-NPE-on-Boat-getStatus.patch deleted file mode 100644 index 19f832054d..0000000000 --- a/patches/server/0852-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/0853-Expand-Pose-API.patch b/patches/server/0853-Expand-Pose-API.patch deleted file mode 100644 index 81b59bbf22..0000000000 --- a/patches/server/0853-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 c7292ddae2a2cb11434a6962706bc2a8dd5d2cdc..aa317a143e2c38a0385a83651a78403401a75d9e 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -428,6 +428,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(); -@@ -626,6 +627,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 0278cd156e3a82df4289f483967512dad63a0644..4c3029a6e4b50afc945797ab23e8c67acba70345 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -895,6 +895,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/0853-More-DragonBattle-API.patch b/patches/server/0853-More-DragonBattle-API.patch new file mode 100644 index 0000000000..a752a4de81 --- /dev/null +++ b/patches/server/0853-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/0854-Add-PlayerPickItemEvent.patch b/patches/server/0854-Add-PlayerPickItemEvent.patch new file mode 100644 index 0000000000..3a9bbc6a05 --- /dev/null +++ b/patches/server/0854-Add-PlayerPickItemEvent.patch @@ -0,0 +1,70 @@ +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 a2c404e4cd808a3a676ae3808852e4105bdc9af4..b5a960f9d1b169a6a39e3ab289e4abf161c3ac2c 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -994,15 +994,25 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + if (stack.isItemEnabled(this.player.level().enabledFeatures())) { + Inventory playerinventory = this.player.getInventory(); + int i = playerinventory.findSlotMatchingItem(stack); ++ // Paper start - Add PlayerPickItemEvent ++ final int sourceSlot = i; ++ final int targetSlot = Inventory.isHotbarSlot(sourceSlot) ? sourceSlot : playerinventory.getSuitableHotbarSlot(); ++ final Player bukkitPlayer = this.player.getBukkitEntity(); ++ final io.papermc.paper.event.player.PlayerPickItemEvent event = new io.papermc.paper.event.player.PlayerPickItemEvent(bukkitPlayer, targetSlot, sourceSlot); ++ if (!event.callEvent()) { ++ return; ++ } ++ i = event.getSourceSlot(); + + if (i != -1) { +- if (Inventory.isHotbarSlot(i)) { +- playerinventory.selected = i; ++ if (Inventory.isHotbarSlot(i) && Inventory.isHotbarSlot(event.getTargetSlot())) { ++ playerinventory.selected = event.getTargetSlot(); + } else { +- playerinventory.pickSlot(i); ++ playerinventory.pickSlot(i, event.getTargetSlot()); + } + } else if (this.player.hasInfiniteMaterials()) { +- playerinventory.addAndPickItem(stack); ++ playerinventory.addAndPickItem(stack, event.getTargetSlot()); ++ // Paper end - Add PlayerPickItemEvent + } + + this.player.connection.send(new ClientboundSetHeldSlotPacket(playerinventory.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 320b6829b8c31bba3c528babe2dd065bdf29581f..39e536d5a9a6fb2cb7654bba8828bdb2c49425dd 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Inventory.java ++++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java +@@ -145,8 +145,10 @@ public class Inventory implements Container, Nameable { + return -1; + } + +- public void addAndPickItem(ItemStack stack) { +- this.selected = this.getSuitableHotbarSlot(); ++ // Paper start - Add PlayerPickItemEvent ++ public void addAndPickItem(ItemStack stack, final int targetSlot) { ++ this.selected = targetSlot; ++ // Paper end - Add PlayerPickItemEvent + if (!((ItemStack) this.items.get(this.selected)).isEmpty()) { + int i = this.getFreeSlot(); + +@@ -158,8 +160,10 @@ public class Inventory implements Container, Nameable { + this.items.set(this.selected, stack); + } + +- public void pickSlot(int slot) { +- this.selected = this.getSuitableHotbarSlot(); ++ // Paper start - Add PlayerPickItemEvent ++ public void pickSlot(int slot, final 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/0854-More-DragonBattle-API.patch b/patches/server/0854-More-DragonBattle-API.patch deleted file mode 100644 index a752a4de81..0000000000 --- a/patches/server/0854-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/0855-Add-PlayerPickItemEvent.patch b/patches/server/0855-Add-PlayerPickItemEvent.patch deleted file mode 100644 index 3a9bbc6a05..0000000000 --- a/patches/server/0855-Add-PlayerPickItemEvent.patch +++ /dev/null @@ -1,70 +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 a2c404e4cd808a3a676ae3808852e4105bdc9af4..b5a960f9d1b169a6a39e3ab289e4abf161c3ac2c 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -994,15 +994,25 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - if (stack.isItemEnabled(this.player.level().enabledFeatures())) { - Inventory playerinventory = this.player.getInventory(); - int i = playerinventory.findSlotMatchingItem(stack); -+ // Paper start - Add PlayerPickItemEvent -+ final int sourceSlot = i; -+ final int targetSlot = Inventory.isHotbarSlot(sourceSlot) ? sourceSlot : playerinventory.getSuitableHotbarSlot(); -+ final Player bukkitPlayer = this.player.getBukkitEntity(); -+ final io.papermc.paper.event.player.PlayerPickItemEvent event = new io.papermc.paper.event.player.PlayerPickItemEvent(bukkitPlayer, targetSlot, sourceSlot); -+ if (!event.callEvent()) { -+ return; -+ } -+ i = event.getSourceSlot(); - - if (i != -1) { -- if (Inventory.isHotbarSlot(i)) { -- playerinventory.selected = i; -+ if (Inventory.isHotbarSlot(i) && Inventory.isHotbarSlot(event.getTargetSlot())) { -+ playerinventory.selected = event.getTargetSlot(); - } else { -- playerinventory.pickSlot(i); -+ playerinventory.pickSlot(i, event.getTargetSlot()); - } - } else if (this.player.hasInfiniteMaterials()) { -- playerinventory.addAndPickItem(stack); -+ playerinventory.addAndPickItem(stack, event.getTargetSlot()); -+ // Paper end - Add PlayerPickItemEvent - } - - this.player.connection.send(new ClientboundSetHeldSlotPacket(playerinventory.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 320b6829b8c31bba3c528babe2dd065bdf29581f..39e536d5a9a6fb2cb7654bba8828bdb2c49425dd 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Inventory.java -+++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java -@@ -145,8 +145,10 @@ public class Inventory implements Container, Nameable { - return -1; - } - -- public void addAndPickItem(ItemStack stack) { -- this.selected = this.getSuitableHotbarSlot(); -+ // Paper start - Add PlayerPickItemEvent -+ public void addAndPickItem(ItemStack stack, final int targetSlot) { -+ this.selected = targetSlot; -+ // Paper end - Add PlayerPickItemEvent - if (!((ItemStack) this.items.get(this.selected)).isEmpty()) { - int i = this.getFreeSlot(); - -@@ -158,8 +160,10 @@ public class Inventory implements Container, Nameable { - this.items.set(this.selected, stack); - } - -- public void pickSlot(int slot) { -- this.selected = this.getSuitableHotbarSlot(); -+ // Paper start - Add PlayerPickItemEvent -+ public void pickSlot(int slot, final 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/0855-Allow-trident-custom-damage.patch b/patches/server/0855-Allow-trident-custom-damage.patch new file mode 100644 index 0000000000..7cdbc23677 --- /dev/null +++ b/patches/server/0855-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 3888f13a49af26b0ece8813b607c20fc380cecd5..1e045397763e8233c2e8f9955468788374b80068 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java +@@ -37,16 +37,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()); + } +@@ -137,7 +140,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/0856-Allow-trident-custom-damage.patch b/patches/server/0856-Allow-trident-custom-damage.patch deleted file mode 100644 index 7cdbc23677..0000000000 --- a/patches/server/0856-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 3888f13a49af26b0ece8813b607c20fc380cecd5..1e045397763e8233c2e8f9955468788374b80068 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -@@ -37,16 +37,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()); - } -@@ -137,7 +140,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/0856-Expose-hand-in-BlockCanBuildEvent.patch b/patches/server/0856-Expose-hand-in-BlockCanBuildEvent.patch new file mode 100644 index 0000000000..6b01456a9d --- /dev/null +++ b/patches/server/0856-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 560932675223ea3ff75b6bf42b47ea5882ff953a..348a05057d418b46598bd09d8563baa781eb318d 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/0857-Expose-hand-in-BlockCanBuildEvent.patch b/patches/server/0857-Expose-hand-in-BlockCanBuildEvent.patch deleted file mode 100644 index 6b01456a9d..0000000000 --- a/patches/server/0857-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 560932675223ea3ff75b6bf42b47ea5882ff953a..348a05057d418b46598bd09d8563baa781eb318d 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/0857-Optimize-nearest-structure-border-iteration.patch b/patches/server/0857-Optimize-nearest-structure-border-iteration.patch new file mode 100644 index 0000000000..8b4cd3484e --- /dev/null +++ b/patches/server/0857-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 c64389acf0764c8d048bea2d99a21a0da832150d..ca6928f959eb63ac9183ba6c95738609839a7d32 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -266,12 +266,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/0858-Implement-OfflinePlayer-isConnected.patch b/patches/server/0858-Implement-OfflinePlayer-isConnected.patch new file mode 100644 index 0000000000..3d4be22227 --- /dev/null +++ b/patches/server/0858-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 006d44e0a1175980f80f6cac0b0f7ed3eef47a52..f49944a4e6cdab26080e6259c5550bda5ff9a7b3 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/0858-Optimize-nearest-structure-border-iteration.patch b/patches/server/0858-Optimize-nearest-structure-border-iteration.patch deleted file mode 100644 index 8b4cd3484e..0000000000 --- a/patches/server/0858-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 c64389acf0764c8d048bea2d99a21a0da832150d..ca6928f959eb63ac9183ba6c95738609839a7d32 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -266,12 +266,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/0859-Fix-slot-desync.patch b/patches/server/0859-Fix-slot-desync.patch new file mode 100644 index 0000000000..6a3b4b7930 --- /dev/null +++ b/patches/server/0859-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 07f14652768d4715eb9053b5a8381816a61b0d28..9eb5848b02fed596af8d5d99d9e5aaf1f1a34a76 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -458,6 +458,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 b5a960f9d1b169a6a39e3ab289e4abf161c3ac2c..b682a766b1e085509d741d6a831a65bf49b6907f 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2813,10 +2813,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 96c252a797a971f36ccaf83ee00da27cf38a2f6c..098a526fdfe92e452f06b66189cd9cbd821198eb 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2783,8 +2783,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 348a05057d418b46598bd09d8563baa781eb318d..4377fa2400c4320e0023ece230090a2a3b4b2ab6 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/0859-Implement-OfflinePlayer-isConnected.patch b/patches/server/0859-Implement-OfflinePlayer-isConnected.patch deleted file mode 100644 index 3d4be22227..0000000000 --- a/patches/server/0859-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 006d44e0a1175980f80f6cac0b0f7ed3eef47a52..f49944a4e6cdab26080e6259c5550bda5ff9a7b3 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/0860-Add-titleOverride-to-InventoryOpenEvent.patch b/patches/server/0860-Add-titleOverride-to-InventoryOpenEvent.patch new file mode 100644 index 0000000000..2c3544fe76 --- /dev/null +++ b/patches/server/0860-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 9eb5848b02fed596af8d5d99d9e5aaf1f1a34a76..0df899728a65db072afd40054ecb86ba72fd5745 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1907,12 +1907,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) { +@@ -1934,7 +1939,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 db99af60c8145cc62f368b06bbc283f24d4dbfb2..e345cdbfab44a0f5da80d738798dbb4424b7ab5c 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 8853f0cfebfe56fd2aa3ec975701b5ffaad46257..b6c30bb70fb4746da024bc4d80b71aeb3558f101 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/0860-Fix-slot-desync.patch b/patches/server/0860-Fix-slot-desync.patch deleted file mode 100644 index 6a3b4b7930..0000000000 --- a/patches/server/0860-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 07f14652768d4715eb9053b5a8381816a61b0d28..9eb5848b02fed596af8d5d99d9e5aaf1f1a34a76 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -458,6 +458,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 b5a960f9d1b169a6a39e3ab289e4abf161c3ac2c..b682a766b1e085509d741d6a831a65bf49b6907f 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2813,10 +2813,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 96c252a797a971f36ccaf83ee00da27cf38a2f6c..098a526fdfe92e452f06b66189cd9cbd821198eb 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2783,8 +2783,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 348a05057d418b46598bd09d8563baa781eb318d..4377fa2400c4320e0023ece230090a2a3b4b2ab6 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/0861-Add-titleOverride-to-InventoryOpenEvent.patch b/patches/server/0861-Add-titleOverride-to-InventoryOpenEvent.patch deleted file mode 100644 index 58b1cc5e7e..0000000000 --- a/patches/server/0861-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 bfaf2cc79afebb0b51f6eb7081de2230546752ef..4c49a7a5dc702e1ab2d1b12f41af7c9ce1368e06 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1907,12 +1907,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) { -@@ -1934,7 +1939,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 db99af60c8145cc62f368b06bbc283f24d4dbfb2..e345cdbfab44a0f5da80d738798dbb4424b7ab5c 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 8853f0cfebfe56fd2aa3ec975701b5ffaad46257..b6c30bb70fb4746da024bc4d80b71aeb3558f101 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/0861-Configure-sniffer-egg-hatch-time.patch b/patches/server/0861-Configure-sniffer-egg-hatch-time.patch new file mode 100644 index 0000000000..e39971b614 --- /dev/null +++ b/patches/server/0861-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/0862-Configure-sniffer-egg-hatch-time.patch b/patches/server/0862-Configure-sniffer-egg-hatch-time.patch deleted file mode 100644 index e39971b614..0000000000 --- a/patches/server/0862-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/0862-Do-crystal-portal-proximity-check-before-entity-look.patch b/patches/server/0862-Do-crystal-portal-proximity-check-before-entity-look.patch new file mode 100644 index 0000000000..0ba2ce3d55 --- /dev/null +++ b/patches/server/0862-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/0863-Do-crystal-portal-proximity-check-before-entity-look.patch b/patches/server/0863-Do-crystal-portal-proximity-check-before-entity-look.patch deleted file mode 100644 index 0ba2ce3d55..0000000000 --- a/patches/server/0863-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/0863-Skip-POI-finding-if-stuck-in-vehicle.patch b/patches/server/0863-Skip-POI-finding-if-stuck-in-vehicle.patch new file mode 100644 index 0000000000..ef5cb8a16f --- /dev/null +++ b/patches/server/0863-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 cd7e68e11c896414fbfa3ea078b258f185511b35..45974895c464b4c0186ab9add5eacb98abe90e09 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 +@@ -70,6 +70,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/0864-Add-slot-sanity-checks-in-container-clicks.patch b/patches/server/0864-Add-slot-sanity-checks-in-container-clicks.patch new file mode 100644 index 0000000000..5b15672a01 --- /dev/null +++ b/patches/server/0864-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 b682a766b1e085509d741d6a831a65bf49b6907f..c442743e70e1985dc596ba948fa97f0475a4c11e 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -3076,6 +3076,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/0864-Skip-POI-finding-if-stuck-in-vehicle.patch b/patches/server/0864-Skip-POI-finding-if-stuck-in-vehicle.patch deleted file mode 100644 index ef5cb8a16f..0000000000 --- a/patches/server/0864-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 cd7e68e11c896414fbfa3ea078b258f185511b35..45974895c464b4c0186ab9add5eacb98abe90e09 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 -@@ -70,6 +70,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/0865-Add-slot-sanity-checks-in-container-clicks.patch b/patches/server/0865-Add-slot-sanity-checks-in-container-clicks.patch deleted file mode 100644 index 5b15672a01..0000000000 --- a/patches/server/0865-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 b682a766b1e085509d741d6a831a65bf49b6907f..c442743e70e1985dc596ba948fa97f0475a4c11e 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3076,6 +3076,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/0865-Call-BlockRedstoneEvents-properly.patch b/patches/server/0865-Call-BlockRedstoneEvents-properly.patch new file mode 100644 index 0000000000..d5fec3e60b --- /dev/null +++ b/patches/server/0865-Call-BlockRedstoneEvents-properly.patch @@ -0,0 +1,42 @@ +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 properly + +Call BlockRedstoneEvents for lecterns. +Fix previous power level for experimental redstone wire. + +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 5f860da758a6954d548bc4e768f39485c2aa4645..9797d756ecf532db013093469a3e40d9c6ac0544 100644 +--- a/src/main/java/net/minecraft/world/level/block/LecternBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/LecternBlock.java +@@ -175,6 +175,16 @@ public class LecternBlock extends BaseEntityBlock { + } + + private static void changePowered(Level world, BlockPos pos, BlockState state, boolean powered) { ++ // Paper start - Call BlockRedstoneEvent properly ++ 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 BlockRedstoneEvent properly + world.setBlock(pos, (BlockState) state.setValue(LecternBlock.POWERED, powered), 3); + LecternBlock.updateBelow(world, pos, state); + } +diff --git a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java +index 28e0ff0a6fef63a572782704d34c4ccefc7baec1..bad91f7e9ebcf9d73f2d74a65e5235ee496e844e 100644 +--- a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java ++++ b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java +@@ -46,7 +46,7 @@ public class ExperimentalRedstoneWireEvaluator extends RedstoneWireEvaluator { + BlockState iblockdata1 = world.getBlockState(blockposition1); + + // CraftBukkit start +- int oldPower = state.getValue(RedStoneWireBlock.POWER); ++ int oldPower = iblockdata1.getValue(RedStoneWireBlock.POWER); // Paper - Call BlockRedstoneEvent properly; get the previous power from the right state + if (oldPower != j) { + BlockRedstoneEvent event = new BlockRedstoneEvent(CraftBlock.at(world, blockposition1), oldPower, j); + world.getCraftServer().getPluginManager().callEvent(event); diff --git a/patches/server/0866-Allow-proper-checking-of-empty-item-stacks.patch b/patches/server/0866-Allow-proper-checking-of-empty-item-stacks.patch new file mode 100644 index 0000000000..85819379c1 --- /dev/null +++ b/patches/server/0866-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/0866-Call-BlockRedstoneEvents-properly.patch b/patches/server/0866-Call-BlockRedstoneEvents-properly.patch deleted file mode 100644 index d5fec3e60b..0000000000 --- a/patches/server/0866-Call-BlockRedstoneEvents-properly.patch +++ /dev/null @@ -1,42 +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 properly - -Call BlockRedstoneEvents for lecterns. -Fix previous power level for experimental redstone wire. - -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 5f860da758a6954d548bc4e768f39485c2aa4645..9797d756ecf532db013093469a3e40d9c6ac0544 100644 ---- a/src/main/java/net/minecraft/world/level/block/LecternBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LecternBlock.java -@@ -175,6 +175,16 @@ public class LecternBlock extends BaseEntityBlock { - } - - private static void changePowered(Level world, BlockPos pos, BlockState state, boolean powered) { -+ // Paper start - Call BlockRedstoneEvent properly -+ 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 BlockRedstoneEvent properly - world.setBlock(pos, (BlockState) state.setValue(LecternBlock.POWERED, powered), 3); - LecternBlock.updateBelow(world, pos, state); - } -diff --git a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java -index 28e0ff0a6fef63a572782704d34c4ccefc7baec1..bad91f7e9ebcf9d73f2d74a65e5235ee496e844e 100644 ---- a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java -+++ b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java -@@ -46,7 +46,7 @@ public class ExperimentalRedstoneWireEvaluator extends RedstoneWireEvaluator { - BlockState iblockdata1 = world.getBlockState(blockposition1); - - // CraftBukkit start -- int oldPower = state.getValue(RedStoneWireBlock.POWER); -+ int oldPower = iblockdata1.getValue(RedStoneWireBlock.POWER); // Paper - Call BlockRedstoneEvent properly; get the previous power from the right state - if (oldPower != j) { - BlockRedstoneEvent event = new BlockRedstoneEvent(CraftBlock.at(world, blockposition1), oldPower, j); - world.getCraftServer().getPluginManager().callEvent(event); diff --git a/patches/server/0867-Allow-proper-checking-of-empty-item-stacks.patch b/patches/server/0867-Allow-proper-checking-of-empty-item-stacks.patch deleted file mode 100644 index 85819379c1..0000000000 --- a/patches/server/0867-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/0867-Fix-silent-equipment-change-for-mobs.patch b/patches/server/0867-Fix-silent-equipment-change-for-mobs.patch new file mode 100644 index 0000000000..ef965e7c29 --- /dev/null +++ b/patches/server/0867-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 7d3e165bae2c00737019689b7bf1e74ad2517270..13064a73a9e3b45d32a098c4179cd980be508abc 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 cb89a95e6ff9db73c912bba04d27657683135153..90b6ed81dcfd4021c7e9509da5e8725034fa07e5 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -265,8 +265,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/0868-Fix-silent-equipment-change-for-mobs.patch b/patches/server/0868-Fix-silent-equipment-change-for-mobs.patch deleted file mode 100644 index ef965e7c29..0000000000 --- a/patches/server/0868-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 7d3e165bae2c00737019689b7bf1e74ad2517270..13064a73a9e3b45d32a098c4179cd980be508abc 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 cb89a95e6ff9db73c912bba04d27657683135153..90b6ed81dcfd4021c7e9509da5e8725034fa07e5 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -265,8 +265,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/0868-Fix-spigot-s-Forced-Stats.patch b/patches/server/0868-Fix-spigot-s-Forced-Stats.patch new file mode 100644 index 0000000000..8e920d0d89 --- /dev/null +++ b/patches/server/0868-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/0869-Add-missing-InventoryHolders-to-inventories.patch b/patches/server/0869-Add-missing-InventoryHolders-to-inventories.patch new file mode 100644 index 0000000000..6464e85d97 --- /dev/null +++ b/patches/server/0869-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 75f097414f436eee9f179d4d03dd64599cbaad6f..b821c2676ecc252f90eff84cad0c4ba2c664531e 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 68f978be8ec11e0e5bb4ea40e06c61f729e92d46..e200df7fc90de06d420556711ac67fa94a40d1d2 100644 +--- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java +@@ -62,7 +62,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 74ea3f0154733ed4f096d88403fe011cca663e02..5dce62aead43c7110e06196423458eea2ba31885 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/0869-Fix-spigot-s-Forced-Stats.patch b/patches/server/0869-Fix-spigot-s-Forced-Stats.patch deleted file mode 100644 index 8e920d0d89..0000000000 --- a/patches/server/0869-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/0870-Add-missing-InventoryHolders-to-inventories.patch b/patches/server/0870-Add-missing-InventoryHolders-to-inventories.patch deleted file mode 100644 index 6464e85d97..0000000000 --- a/patches/server/0870-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 75f097414f436eee9f179d4d03dd64599cbaad6f..b821c2676ecc252f90eff84cad0c4ba2c664531e 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 68f978be8ec11e0e5bb4ea40e06c61f729e92d46..e200df7fc90de06d420556711ac67fa94a40d1d2 100644 ---- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -@@ -62,7 +62,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 74ea3f0154733ed4f096d88403fe011cca663e02..5dce62aead43c7110e06196423458eea2ba31885 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/0870-Do-not-read-tile-entities-in-chunks-that-are-positio.patch b/patches/server/0870-Do-not-read-tile-entities-in-chunks-that-are-positio.patch new file mode 100644 index 0000000000..c55e56d157 --- /dev/null +++ b/patches/server/0870-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/0871-Add-missing-logs-for-log-ips-config-option.patch b/patches/server/0871-Add-missing-logs-for-log-ips-config-option.patch new file mode 100644 index 0000000000..2898d66615 --- /dev/null +++ b/patches/server/0871-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/0871-Do-not-read-tile-entities-in-chunks-that-are-positio.patch b/patches/server/0871-Do-not-read-tile-entities-in-chunks-that-are-positio.patch deleted file mode 100644 index c55e56d157..0000000000 --- a/patches/server/0871-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/0872-Add-missing-logs-for-log-ips-config-option.patch b/patches/server/0872-Add-missing-logs-for-log-ips-config-option.patch deleted file mode 100644 index 2898d66615..0000000000 --- a/patches/server/0872-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/0872-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch b/patches/server/0872-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch new file mode 100644 index 0000000000..b6ec32df61 --- /dev/null +++ b/patches/server/0872-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/0873-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch b/patches/server/0873-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch new file mode 100644 index 0000000000..7ccf4c0f03 --- /dev/null +++ b/patches/server/0873-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/0873-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch b/patches/server/0873-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch deleted file mode 100644 index b6ec32df61..0000000000 --- a/patches/server/0873-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/0874-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch b/patches/server/0874-Fix-NPE-in-AdvancementProgress-getDateAwarded.patch deleted file mode 100644 index 7ccf4c0f03..0000000000 --- a/patches/server/0874-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/0874-Fix-team-sidebar-objectives-not-being-cleared.patch b/patches/server/0874-Fix-team-sidebar-objectives-not-being-cleared.patch new file mode 100644 index 0000000000..cebe7aefc2 --- /dev/null +++ b/patches/server/0874-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/0875-Fix-missing-map-initialize-event-call.patch b/patches/server/0875-Fix-missing-map-initialize-event-call.patch new file mode 100644 index 0000000000..f9d9852b1b --- /dev/null +++ b/patches/server/0875-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 9b4e3144b062007b936b3b444320646061cc0133..2a56e7846b3def7d1e9a2d5e473a6806a1acec28 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1711,13 +1711,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/0875-Fix-team-sidebar-objectives-not-being-cleared.patch b/patches/server/0875-Fix-team-sidebar-objectives-not-being-cleared.patch deleted file mode 100644 index cebe7aefc2..0000000000 --- a/patches/server/0875-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 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/0876-Fix-missing-map-initialize-event-call.patch b/patches/server/0876-Fix-missing-map-initialize-event-call.patch deleted file mode 100644 index f9d9852b1b..0000000000 --- a/patches/server/0876-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 9b4e3144b062007b936b3b444320646061cc0133..2a56e7846b3def7d1e9a2d5e473a6806a1acec28 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1711,13 +1711,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/0876-Update-entity-data-when-attaching-firework-to-entity.patch b/patches/server/0876-Update-entity-data-when-attaching-firework-to-entity.patch new file mode 100644 index 0000000000..f2c094976f --- /dev/null +++ b/patches/server/0876-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/0877-Fix-UnsafeValues-loadAdvancement.patch b/patches/server/0877-Fix-UnsafeValues-loadAdvancement.patch new file mode 100644 index 0000000000..0da2e5aca2 --- /dev/null +++ b/patches/server/0877-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 cd00165ebb193c788e05a6f0b2b649936d56aa9f..066d8f0592fa4fc9886eab7ca1ba1151b3748b95 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -303,9 +303,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/0877-Update-entity-data-when-attaching-firework-to-entity.patch b/patches/server/0877-Update-entity-data-when-attaching-firework-to-entity.patch deleted file mode 100644 index f2c094976f..0000000000 --- a/patches/server/0877-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/0878-Add-player-idle-duration-API.patch b/patches/server/0878-Add-player-idle-duration-API.patch new file mode 100644 index 0000000000..7d46c27071 --- /dev/null +++ b/patches/server/0878-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 f49944a4e6cdab26080e6259c5550bda5ff9a7b3..06d5472a19e80fc363df10df936f1f03805e78d7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -3416,6 +3416,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/0878-Fix-UnsafeValues-loadAdvancement.patch b/patches/server/0878-Fix-UnsafeValues-loadAdvancement.patch deleted file mode 100644 index 0da2e5aca2..0000000000 --- a/patches/server/0878-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 cd00165ebb193c788e05a6f0b2b649936d56aa9f..066d8f0592fa4fc9886eab7ca1ba1151b3748b95 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -303,9 +303,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/0879-Add-player-idle-duration-API.patch b/patches/server/0879-Add-player-idle-duration-API.patch deleted file mode 100644 index 7d46c27071..0000000000 --- a/patches/server/0879-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 f49944a4e6cdab26080e6259c5550bda5ff9a7b3..06d5472a19e80fc363df10df936f1f03805e78d7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3416,6 +3416,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/0879-Don-t-check-if-we-can-see-non-visible-entities.patch b/patches/server/0879-Don-t-check-if-we-can-see-non-visible-entities.patch new file mode 100644 index 0000000000..f93e6dba80 --- /dev/null +++ b/patches/server/0879-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 054c962288585ef3d0249d68c24d85624f172374..1c76e0d54320c3aa358159a1590d4701d4f18e9e 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1584,7 +1584,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/0880-Don-t-check-if-we-can-see-non-visible-entities.patch b/patches/server/0880-Don-t-check-if-we-can-see-non-visible-entities.patch deleted file mode 100644 index f93e6dba80..0000000000 --- a/patches/server/0880-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 054c962288585ef3d0249d68c24d85624f172374..1c76e0d54320c3aa358159a1590d4701d4f18e9e 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1584,7 +1584,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/0880-Fix-NPE-in-SculkBloomEvent-world-access.patch b/patches/server/0880-Fix-NPE-in-SculkBloomEvent-world-access.patch new file mode 100644 index 0000000000..3f44bad4f1 --- /dev/null +++ b/patches/server/0880-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/0881-Allow-null-itemstack-for-Player-sendEquipmentChange.patch b/patches/server/0881-Allow-null-itemstack-for-Player-sendEquipmentChange.patch new file mode 100644 index 0000000000..8d4340bc13 --- /dev/null +++ b/patches/server/0881-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 06d5472a19e80fc363df10df936f1f03805e78d7..4e071f8561f730d21a384406bd2d27a898c87a06 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1134,7 +1134,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/0881-Fix-NPE-in-SculkBloomEvent-world-access.patch b/patches/server/0881-Fix-NPE-in-SculkBloomEvent-world-access.patch deleted file mode 100644 index 3f44bad4f1..0000000000 --- a/patches/server/0881-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/0882-Allow-null-itemstack-for-Player-sendEquipmentChange.patch b/patches/server/0882-Allow-null-itemstack-for-Player-sendEquipmentChange.patch deleted file mode 100644 index 8d4340bc13..0000000000 --- a/patches/server/0882-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 06d5472a19e80fc363df10df936f1f03805e78d7..4e071f8561f730d21a384406bd2d27a898c87a06 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1134,7 +1134,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/0882-Optimize-VarInts.patch b/patches/server/0882-Optimize-VarInts.patch new file mode 100644 index 0000000000..b96957d432 --- /dev/null +++ b/patches/server/0882-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/0883-Add-API-to-get-the-collision-shape-of-a-block-before.patch b/patches/server/0883-Add-API-to-get-the-collision-shape-of-a-block-before.patch new file mode 100644 index 0000000000..bc760b1a56 --- /dev/null +++ b/patches/server/0883-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 fd941d9e38fa6c886b6779eaa63eebe00e1fa1b5..66e40149a59c4bd5d5ca3b5a69c733eea49fb86b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +@@ -688,6 +688,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/0883-Optimize-VarInts.patch b/patches/server/0883-Optimize-VarInts.patch deleted file mode 100644 index b96957d432..0000000000 --- a/patches/server/0883-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/0884-Add-API-to-get-the-collision-shape-of-a-block-before.patch b/patches/server/0884-Add-API-to-get-the-collision-shape-of-a-block-before.patch deleted file mode 100644 index bc760b1a56..0000000000 --- a/patches/server/0884-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 fd941d9e38fa6c886b6779eaa63eebe00e1fa1b5..66e40149a59c4bd5d5ca3b5a69c733eea49fb86b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java -@@ -688,6 +688,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/0884-Add-predicate-for-blocks-when-raytracing.patch b/patches/server/0884-Add-predicate-for-blocks-when-raytracing.patch new file mode 100644 index 0000000000..52e7d29745 --- /dev/null +++ b/patches/server/0884-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 e69473307b30d2b805fc1723ae8f6f2be76310ef..62719778c62d6632a8eb6f2bc670956c15a247de 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 231089eab86f5d3e33ddb6d5cb8358d5d5d5eaf4..a36470d9e9d36106c928f39f7eddc7afe3621610 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1097,9 +1097,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(); +@@ -1149,9 +1155,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(); +@@ -1164,16 +1177,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/0885-Add-predicate-for-blocks-when-raytracing.patch b/patches/server/0885-Add-predicate-for-blocks-when-raytracing.patch deleted file mode 100644 index 52e7d29745..0000000000 --- a/patches/server/0885-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 e69473307b30d2b805fc1723ae8f6f2be76310ef..62719778c62d6632a8eb6f2bc670956c15a247de 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 231089eab86f5d3e33ddb6d5cb8358d5d5d5eaf4..a36470d9e9d36106c928f39f7eddc7afe3621610 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1097,9 +1097,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(); -@@ -1149,9 +1155,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(); -@@ -1164,16 +1177,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/0885-Broadcast-take-item-packets-with-collector-as-source.patch b/patches/server/0885-Broadcast-take-item-packets-with-collector-as-source.patch new file mode 100644 index 0000000000..bbba71fa10 --- /dev/null +++ b/patches/server/0885-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 4e0eb1f0103823a764c184142744a290c0ebed53..70574115423d95c9efabf77e4113e65e81f8c0d1 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3903,7 +3903,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/0886-Broadcast-take-item-packets-with-collector-as-source.patch b/patches/server/0886-Broadcast-take-item-packets-with-collector-as-source.patch deleted file mode 100644 index bbba71fa10..0000000000 --- a/patches/server/0886-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 4e0eb1f0103823a764c184142744a290c0ebed53..70574115423d95c9efabf77e4113e65e81f8c0d1 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3903,7 +3903,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/0886-Expand-LingeringPotion-API.patch b/patches/server/0886-Expand-LingeringPotion-API.patch new file mode 100644 index 0000000000..3a58f0528a --- /dev/null +++ b/patches/server/0886-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/0887-Expand-LingeringPotion-API.patch b/patches/server/0887-Expand-LingeringPotion-API.patch deleted file mode 100644 index 3a58f0528a..0000000000 --- a/patches/server/0887-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/0887-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch b/patches/server/0887-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch new file mode 100644 index 0000000000..50b3a3d9a2 --- /dev/null +++ b/patches/server/0887-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 a36470d9e9d36106c928f39f7eddc7afe3621610..b7d30e9578b01672a8485077a2d093fa744e802c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -723,7 +723,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/0888-Add-hand-to-fish-event-for-all-player-interactions.patch b/patches/server/0888-Add-hand-to-fish-event-for-all-player-interactions.patch new file mode 100644 index 0000000000..49bef0d9a5 --- /dev/null +++ b/patches/server/0888-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 a2487ca0d7794e58d9ede35d9be5a05a7ea7b03c..dcf60d2499957d4803e4b395603da45e81076095 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 54a71bd8c5e7eefb3c008664fb886f4887073dbb..06b66e68d33928c41f0289a67c8c3aad87811ac9 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/0888-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch b/patches/server/0888-Fix-strikeLightningEffect-powers-lightning-rods-and-.patch deleted file mode 100644 index 50b3a3d9a2..0000000000 --- a/patches/server/0888-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 a36470d9e9d36106c928f39f7eddc7afe3621610..b7d30e9578b01672a8485077a2d093fa744e802c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -723,7 +723,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/0889-Add-hand-to-fish-event-for-all-player-interactions.patch b/patches/server/0889-Add-hand-to-fish-event-for-all-player-interactions.patch deleted file mode 100644 index 49bef0d9a5..0000000000 --- a/patches/server/0889-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 a2487ca0d7794e58d9ede35d9be5a05a7ea7b03c..dcf60d2499957d4803e4b395603da45e81076095 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 54a71bd8c5e7eefb3c008664fb886f4887073dbb..06b66e68d33928c41f0289a67c8c3aad87811ac9 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/0889-Fix-several-issues-with-EntityBreedEvent.patch b/patches/server/0889-Fix-several-issues-with-EntityBreedEvent.patch new file mode 100644 index 0000000000..7d7a988fc0 --- /dev/null +++ b/patches/server/0889-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/0890-Fix-several-issues-with-EntityBreedEvent.patch b/patches/server/0890-Fix-several-issues-with-EntityBreedEvent.patch deleted file mode 100644 index 7d7a988fc0..0000000000 --- a/patches/server/0890-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/0891-Fix-missing-event-call-for-entity-teleport-API.patch b/patches/server/0891-Fix-missing-event-call-for-entity-teleport-API.patch new file mode 100644 index 0000000000..5eaf062157 --- /dev/null +++ b/patches/server/0891-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 4c3029a6e4b50afc945797ab23e8c67acba70345..2298b3203ce6bf8aca9f819fe27ab5ef6594dbed 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/0892-Fix-missing-event-call-for-entity-teleport-API.patch b/patches/server/0892-Fix-missing-event-call-for-entity-teleport-API.patch deleted file mode 100644 index 5eaf062157..0000000000 --- a/patches/server/0892-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 4c3029a6e4b50afc945797ab23e8c67acba70345..2298b3203ce6bf8aca9f819fe27ab5ef6594dbed 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/0892-Lazily-create-LootContext-for-criterions.patch b/patches/server/0892-Lazily-create-LootContext-for-criterions.patch new file mode 100644 index 0000000000..d1033bf7e7 --- /dev/null +++ b/patches/server/0892-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/0893-Don-t-fire-sync-events-during-worldgen.patch b/patches/server/0893-Don-t-fire-sync-events-during-worldgen.patch new file mode 100644 index 0000000000..875d04d629 --- /dev/null +++ b/patches/server/0893-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 2a56e7846b3def7d1e9a2d5e473a6806a1acec28..48566fa87db695517214e17b560c84d78f0130bf 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1195,6 +1195,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 098a526fdfe92e452f06b66189cd9cbd821198eb..b1145c1da1d2432f261804b335fe204d4b4247f6 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -632,7 +632,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 979c99851ccb363d889069bafa5b5f7eb6b1a436..2cd74db8e3c51c97a2abcb801bb5c15cd55ca8f9 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityType.java ++++ b/src/main/java/net/minecraft/world/entity/EntityType.java +@@ -659,9 +659,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 70574115423d95c9efabf77e4113e65e81f8c0d1..1618c415f5f9b356206f0e2f1474545f31dfbb01 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/0893-Lazily-create-LootContext-for-criterions.patch b/patches/server/0893-Lazily-create-LootContext-for-criterions.patch deleted file mode 100644 index d1033bf7e7..0000000000 --- a/patches/server/0893-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/0894-Add-Structure-check-API.patch b/patches/server/0894-Add-Structure-check-API.patch new file mode 100644 index 0000000000..cac7acf30a --- /dev/null +++ b/patches/server/0894-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 b7d30e9578b01672a8485077a2d093fa744e802c..6689656098a83d5fe39762caaa6d4924249968ce 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -243,6 +243,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/0894-Don-t-fire-sync-events-during-worldgen.patch b/patches/server/0894-Don-t-fire-sync-events-during-worldgen.patch deleted file mode 100644 index a8e936d27c..0000000000 --- a/patches/server/0894-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 1197788c4e0cc8740e69cfcc36d731bf6bc9fcb1..97f1722ed5566dcb8c7e0ccdefea1f89574eb12e 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1195,6 +1195,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 1c070437ef763b56791d61b8c36e623c3dc80649..ea4a31e08452a311798ace8554cfa16e41acf15c 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -632,7 +632,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 979c99851ccb363d889069bafa5b5f7eb6b1a436..2cd74db8e3c51c97a2abcb801bb5c15cd55ca8f9 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -659,9 +659,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 70574115423d95c9efabf77e4113e65e81f8c0d1..1618c415f5f9b356206f0e2f1474545f31dfbb01 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/0895-Add-Structure-check-API.patch b/patches/server/0895-Add-Structure-check-API.patch deleted file mode 100644 index cac7acf30a..0000000000 --- a/patches/server/0895-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 b7d30e9578b01672a8485077a2d093fa744e802c..6689656098a83d5fe39762caaa6d4924249968ce 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -243,6 +243,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/0895-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch b/patches/server/0895-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch new file mode 100644 index 0000000000..7490845b11 --- /dev/null +++ b/patches/server/0895-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 fba042d6934f7e871114c81f97a6ac88a9b59212..f129d714c1a815f348669dc13a5cd4d360e8ed6a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -1685,7 +1685,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/0896-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch b/patches/server/0896-Fix-CraftMetaItem-getAttributeModifier-duplication-c.patch deleted file mode 100644 index 7490845b11..0000000000 --- a/patches/server/0896-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 fba042d6934f7e871114c81f97a6ac88a9b59212..f129d714c1a815f348669dc13a5cd4d360e8ed6a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -1685,7 +1685,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/0896-Restore-vanilla-entity-drops-behavior.patch b/patches/server/0896-Restore-vanilla-entity-drops-behavior.patch new file mode 100644 index 0000000000..8b3b48ea0a --- /dev/null +++ b/patches/server/0896-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 0df899728a65db072afd40054ecb86ba72fd5745..ebef3db3e42d3cb8c36ace390af0fc90a5405d26 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -1232,20 +1232,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 b1145c1da1d2432f261804b335fe204d4b4247f6..16e3554ae5e729f5e561a95156a27dcdbf97e141 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2704,19 +2704,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 1618c415f5f9b356206f0e2f1474545f31dfbb01..d32e5b1aa7549751e192b79c238c1832d6e9e605 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -287,7 +287,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 fa8c7a7f71621437bec2ce69c3ad24b495ceed1d..9fac1c16356ab994462852aeb9c42bf32996bbde 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 +@@ -535,10 +535,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 b6c30bb70fb4746da024bc4d80b71aeb3558f101..1c87019f5eb8e51accef3dc7ee949cdf2bec8f72 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/0897-Dont-resend-blocks-on-interactions.patch b/patches/server/0897-Dont-resend-blocks-on-interactions.patch new file mode 100644 index 0000000000..233b0fcc64 --- /dev/null +++ b/patches/server/0897-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 30ba2750e884ceff89e87e2155f18ea66a05ee36..fd5b6a94693bbbf14be39e63025ebd4c44530e2d 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -511,10 +511,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/0897-Restore-vanilla-entity-drops-behavior.patch b/patches/server/0897-Restore-vanilla-entity-drops-behavior.patch deleted file mode 100644 index 2ba631968a..0000000000 --- a/patches/server/0897-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 4c49a7a5dc702e1ab2d1b12f41af7c9ce1368e06..d82a22d9ef5a7f649d424c01e88a12094ce0a41f 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1232,20 +1232,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 ea4a31e08452a311798ace8554cfa16e41acf15c..c5724826fade3ade6fea3d4f6173b46fdeaf9679 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2704,19 +2704,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 1618c415f5f9b356206f0e2f1474545f31dfbb01..d32e5b1aa7549751e192b79c238c1832d6e9e605 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -287,7 +287,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 fa8c7a7f71621437bec2ce69c3ad24b495ceed1d..9fac1c16356ab994462852aeb9c42bf32996bbde 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 -@@ -535,10 +535,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 b6c30bb70fb4746da024bc4d80b71aeb3558f101..1c87019f5eb8e51accef3dc7ee949cdf2bec8f72 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/0898-Dont-resend-blocks-on-interactions.patch b/patches/server/0898-Dont-resend-blocks-on-interactions.patch deleted file mode 100644 index 233b0fcc64..0000000000 --- a/patches/server/0898-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 30ba2750e884ceff89e87e2155f18ea66a05ee36..fd5b6a94693bbbf14be39e63025ebd4c44530e2d 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -511,10 +511,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/0898-add-more-scoreboard-API.patch b/patches/server/0898-add-more-scoreboard-API.patch new file mode 100644 index 0000000000..3365b53a36 --- /dev/null +++ b/patches/server/0898-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/0899-Improve-Registry.patch b/patches/server/0899-Improve-Registry.patch new file mode 100644 index 0000000000..5546233da5 --- /dev/null +++ b/patches/server/0899-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 249f0dcad04a35244da6dab837a461bb42aad00a..273844c9071b8d5cf6009c6c94a6c47a9d0cc700 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -152,6 +152,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 +@@ -200,6 +201,7 @@ public class CraftRegistry implements Registry { + } + + this.cache.put(namespacedKey, bukkit); ++ this.byValue.put(bukkit, namespacedKey); // Paper - improve Registry + + return bukkit; + } +@@ -232,4 +234,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/0899-add-more-scoreboard-API.patch b/patches/server/0899-add-more-scoreboard-API.patch deleted file mode 100644 index 3365b53a36..0000000000 --- a/patches/server/0899-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/0900-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch b/patches/server/0900-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch new file mode 100644 index 0000000000..77af9e78a8 --- /dev/null +++ b/patches/server/0900-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 d32e5b1aa7549751e192b79c238c1832d6e9e605..2715ba6325ecf82dee237bb53372e3aac3972112 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -4371,7 +4371,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 5bcdeb3eb463d637b16abfb43d5489c0334b6673..68224d1cdabdaf04e4d26dd07e222a312e8fc898 100644 +--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java +@@ -321,7 +321,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 74fa6d2b569b42ac2dbb7efb10df658b9ffeecc4..5e6b66a12af7618fd55b4e32577d718849008b19 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 249f0dcad04a35244da6dab837a461bb42aad00a..273844c9071b8d5cf6009c6c94a6c47a9d0cc700 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -152,6 +152,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 -@@ -200,6 +201,7 @@ public class CraftRegistry implements Registry { - } - - this.cache.put(namespacedKey, bukkit); -+ this.byValue.put(bukkit, namespacedKey); // Paper - improve Registry - - return bukkit; - } -@@ -232,4 +234,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/0901-Add-experience-points-API.patch b/patches/server/0901-Add-experience-points-API.patch new file mode 100644 index 0000000000..61c6907b76 --- /dev/null +++ b/patches/server/0901-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 7dd601d0b0efd285a913a074ffa42e142bda8889..bba669666bbd0f116d1efacfb8d987dd71b6535c 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -1826,7 +1826,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 4e071f8561f730d21a384406bd2d27a898c87a06..6ff46062d6ce6401acdbae8f087075788538802a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1933,6 +1933,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/0901-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch b/patches/server/0901-Fix-NPE-on-null-loc-for-EntityTeleportEvent.patch deleted file mode 100644 index 77af9e78a8..0000000000 --- a/patches/server/0901-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 d32e5b1aa7549751e192b79c238c1832d6e9e605..2715ba6325ecf82dee237bb53372e3aac3972112 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -4371,7 +4371,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 5bcdeb3eb463d637b16abfb43d5489c0334b6673..68224d1cdabdaf04e4d26dd07e222a312e8fc898 100644 ---- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -@@ -321,7 +321,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 74fa6d2b569b42ac2dbb7efb10df658b9ffeecc4..5e6b66a12af7618fd55b4e32577d718849008b19 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 a0f0571bec7f95e2eacb5d4d827b189387e06ef5..b04532aa04aec6ebbff74d64abb73189c2e12016 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java +@@ -45,6 +45,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 +@@ -127,11 +128,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)); + } +@@ -169,22 +177,30 @@ 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(drop -> { ++ 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 eb6233812c8adb575691376b132d8b11b8ce971a..344e739c77a2c54a6e0640fcee2b0f8f19a9b4b4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java +@@ -166,11 +166,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; +@@ -185,11 +192,28 @@ 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); ++ ItemEntity entityitem = this.spawnAtLocation(worldserver1, itemstack1, 1.0F); // Paper - custom drops - copy already done above + this.forceDrops = false; // CraftBukkit + + if (entityitem != null) { +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 be029746905aeba218684b883282649089657de3..975477663b6d76a69c006a89e440e21471b39b89 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 // Paper - no longer needed ++ 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,14 +147,33 @@ 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) { ++ // Paper start - custom shear drops ++ private void spawnShearedMushrooms(ServerLevel world, ItemStack shears, java.util.List drops) { ++ final ServerLevel worldserver1 = world; // Named for lambda consumption + this.forceDrops = true; // Paper - Add missing forceDrop toggles +- this.dropFromShearingLootTable(world, BuiltInLootTables.BOGGED_SHEAR, shears, (worldserver1, itemstack1) -> { ++ drops.forEach(itemstack1 -> { ++ // Paper end - custom shear drops + this.spawnAtLocation(worldserver1, itemstack1, this.getBbHeight()); + }); + this.forceDrops = false; // Paper - Add missing forceDrop toggles +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 1c87019f5eb8e51accef3dc7ee949cdf2bec8f72..ea4e1bf4bfe003c102ecce5958131aa86ec83864 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/0902-Add-experience-points-API.patch b/patches/server/0902-Add-experience-points-API.patch deleted file mode 100644 index 61c6907b76..0000000000 --- a/patches/server/0902-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 7dd601d0b0efd285a913a074ffa42e142bda8889..bba669666bbd0f116d1efacfb8d987dd71b6535c 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -1826,7 +1826,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 4e071f8561f730d21a384406bd2d27a898c87a06..6ff46062d6ce6401acdbae8f087075788538802a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1933,6 +1933,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/0903-Add-PlayerShieldDisableEvent.patch b/patches/server/0903-Add-PlayerShieldDisableEvent.patch new file mode 100644 index 0000000000..57e60cbd4c --- /dev/null +++ b/patches/server/0903-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 bba669666bbd0f116d1efacfb8d987dd71b6535c..5b8b85a295a08ae495f729c595b3a78778965342 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -973,7 +973,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 + } + + } +@@ -1466,8 +1466,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/0903-Add-drops-to-shear-events.patch b/patches/server/0903-Add-drops-to-shear-events.patch deleted file mode 100644 index caeec5beb3..0000000000 --- a/patches/server/0903-Add-drops-to-shear-events.patch +++ /dev/null @@ -1,403 +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 a0f0571bec7f95e2eacb5d4d827b189387e06ef5..b04532aa04aec6ebbff74d64abb73189c2e12016 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -@@ -45,6 +45,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 -@@ -127,11 +128,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)); - } -@@ -169,22 +177,30 @@ 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(drop -> { -+ 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 eb6233812c8adb575691376b132d8b11b8ce971a..344e739c77a2c54a6e0640fcee2b0f8f19a9b4b4 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -@@ -166,11 +166,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; -@@ -185,11 +192,28 @@ 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); -+ ItemEntity entityitem = this.spawnAtLocation(worldserver1, itemstack1, 1.0F); // Paper - custom drops - copy already done above - this.forceDrops = false; // CraftBukkit - - if (entityitem != null) { -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 be029746905aeba218684b883282649089657de3..975477663b6d76a69c006a89e440e21471b39b89 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 // Paper - no longer needed -+ 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,14 +147,33 @@ 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) { -+ // Paper start - custom shear drops -+ private void spawnShearedMushrooms(ServerLevel world, ItemStack shears, java.util.List drops) { -+ final ServerLevel worldserver1 = world; // Named for lambda consumption - this.forceDrops = true; // Paper - Add missing forceDrop toggles -- this.dropFromShearingLootTable(world, BuiltInLootTables.BOGGED_SHEAR, shears, (worldserver1, itemstack1) -> { -+ drops.forEach(itemstack1 -> { -+ // Paper end - custom shear drops - this.spawnAtLocation(worldserver1, itemstack1, this.getBbHeight()); - }); - this.forceDrops = false; // Paper - Add missing forceDrop toggles -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 1c87019f5eb8e51accef3dc7ee949cdf2bec8f72..ea4e1bf4bfe003c102ecce5958131aa86ec83864 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/0904-Add-PlayerShieldDisableEvent.patch b/patches/server/0904-Add-PlayerShieldDisableEvent.patch deleted file mode 100644 index 57e60cbd4c..0000000000 --- a/patches/server/0904-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 bba669666bbd0f116d1efacfb8d987dd71b6535c..5b8b85a295a08ae495f729c595b3a78778965342 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -973,7 +973,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 - } - - } -@@ -1466,8 +1466,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/0904-Validate-ResourceLocation-in-NBT-reading.patch b/patches/server/0904-Validate-ResourceLocation-in-NBT-reading.patch new file mode 100644 index 0000000000..670efb3867 --- /dev/null +++ b/patches/server/0904-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 2cd74db8e3c51c97a2abcb801bb5c15cd55ca8f9..0ec3e1837e36d17e9ff33e7d50c66353aa7539db 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityType.java ++++ b/src/main/java/net/minecraft/world/entity/EntityType.java +@@ -690,7 +690,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 68b869c5d76aeb390a05b053eef70486bd4126fd..48f89ec0f02b85092d03fddeec961f1eba5d4a2a 100644 +--- a/src/main/java/net/minecraft/world/entity/Leashable.java ++++ b/src/main/java/net/minecraft/world/entity/Leashable.java +@@ -65,7 +65,13 @@ public interface Leashable { + @Nullable + private static Leashable.LeashData readLeashDataInternal(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 2715ba6325ecf82dee237bb53372e3aac3972112..95c2e2d73aefcf7c436fad3066e1fedc7299faa1 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 13064a73a9e3b45d32a098c4179cd980be508abc..a66ed6527d95b9c40b6c5983455fc078fd9eb2bf 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -609,7 +609,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + 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 + } else { + this.lootTable = Optional.empty(); + } +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 758fa49f9b420fdbb583ca3443b81ca151478ea8..6edb5a76a503242a6528875184ccd62d6499205f 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -710,7 +710,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 5fe0879efb35970e49d0654c4cb27195c6cc88a4..a9809c18233d82f910735e59363a49de488defcd 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 +@@ -178,7 +178,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/0905-Properly-handle-experience-dropping-on-block-break.patch b/patches/server/0905-Properly-handle-experience-dropping-on-block-break.patch new file mode 100644 index 0000000000..6c91059eb0 --- /dev/null +++ b/patches/server/0905-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 c6133407f515f53c9fa67b988d4758d8f3d89f23..bfedc52cf8f0416fa2aaf73f694122b9eed09a4e 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -616,7 +616,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 0189ff670d84df375399c492467fd4d5c62eff09..537adbef6fdefde170c614aa465b94ff29dfe9f0 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 7e62dcef2902463c7f67aa20cdb78ea9cf4c44f6..cc5be3e8c673409226584328d3e78fccf4ccc2f5 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 +@@ -1184,6 +1184,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/0905-Validate-ResourceLocation-in-NBT-reading.patch b/patches/server/0905-Validate-ResourceLocation-in-NBT-reading.patch deleted file mode 100644 index 670efb3867..0000000000 --- a/patches/server/0905-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 2cd74db8e3c51c97a2abcb801bb5c15cd55ca8f9..0ec3e1837e36d17e9ff33e7d50c66353aa7539db 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -690,7 +690,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 68b869c5d76aeb390a05b053eef70486bd4126fd..48f89ec0f02b85092d03fddeec961f1eba5d4a2a 100644 ---- a/src/main/java/net/minecraft/world/entity/Leashable.java -+++ b/src/main/java/net/minecraft/world/entity/Leashable.java -@@ -65,7 +65,13 @@ public interface Leashable { - @Nullable - private static Leashable.LeashData readLeashDataInternal(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 2715ba6325ecf82dee237bb53372e3aac3972112..95c2e2d73aefcf7c436fad3066e1fedc7299faa1 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 13064a73a9e3b45d32a098c4179cd980be508abc..a66ed6527d95b9c40b6c5983455fc078fd9eb2bf 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -609,7 +609,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab - 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 - } else { - this.lootTable = Optional.empty(); - } -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 758fa49f9b420fdbb583ca3443b81ca151478ea8..6edb5a76a503242a6528875184ccd62d6499205f 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -710,7 +710,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 5fe0879efb35970e49d0654c4cb27195c6cc88a4..a9809c18233d82f910735e59363a49de488defcd 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 -@@ -178,7 +178,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/0906-Fixup-NamespacedKey-handling.patch b/patches/server/0906-Fixup-NamespacedKey-handling.patch new file mode 100644 index 0000000000..2de1c49d0b --- /dev/null +++ b/patches/server/0906-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 273844c9071b8d5cf6009c6c94a6c47a9d0cc700..45c78c113e881b277e1216293ad918ee40b44325 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -127,6 +127,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 9ab615347e241ac264fb70f43306075907420885..0d04f0a34d1d1894845b720a407f7190ea78d514 100644 +--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java +@@ -33,6 +33,7 @@ public class CraftAttribute implements Attribute, Handleable 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..b1b139b773b37e6ec2afea85c500387d6ba9800e 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 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/0906-Properly-handle-experience-dropping-on-block-break.patch b/patches/server/0906-Properly-handle-experience-dropping-on-block-break.patch deleted file mode 100644 index 6c91059eb0..0000000000 --- a/patches/server/0906-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 c6133407f515f53c9fa67b988d4758d8f3d89f23..bfedc52cf8f0416fa2aaf73f694122b9eed09a4e 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -616,7 +616,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 0189ff670d84df375399c492467fd4d5c62eff09..537adbef6fdefde170c614aa465b94ff29dfe9f0 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 7e62dcef2902463c7f67aa20cdb78ea9cf4c44f6..cc5be3e8c673409226584328d3e78fccf4ccc2f5 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 -@@ -1184,6 +1184,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/0907-Expose-LootTable-of-DecoratedPot.patch b/patches/server/0907-Expose-LootTable-of-DecoratedPot.patch new file mode 100644 index 0000000000..afa86977a9 --- /dev/null +++ b/patches/server/0907-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 273844c9071b8d5cf6009c6c94a6c47a9d0cc700..45c78c113e881b277e1216293ad918ee40b44325 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -127,6 +127,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 9ab615347e241ac264fb70f43306075907420885..0d04f0a34d1d1894845b720a407f7190ea78d514 100644 ---- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java -+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java -@@ -33,6 +33,7 @@ public class CraftAttribute implements Attribute, Handleable 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..b1b139b773b37e6ec2afea85c500387d6ba9800e 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 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/0908-Expose-LootTable-of-DecoratedPot.patch b/patches/server/0908-Expose-LootTable-of-DecoratedPot.patch deleted file mode 100644 index afa86977a9..0000000000 --- a/patches/server/0908-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 1c76e0d54320c3aa358159a1590d4701d4f18e9e..e9b585387f6cbc454e7b16feb36a256e733c5488 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1566,10 +1566,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 12d5af9dc6e5d5ed4ea427384226dc5d022550ba..ce3e359ed2b29674aa89a714ee1fb0875d83595d 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/0909-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch b/patches/server/0909-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch new file mode 100644 index 0000000000..fe27657709 --- /dev/null +++ b/patches/server/0909-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 5ea56c6048a356d84472ef0e744af41fe063ccc7..3c037cabd8331eb96a6523b37abab4e73ab79a02 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 5c1f2496f3d4123f6e69239820dd759db0af420e..54c43acb3c401a9b616f4d1b871d7c4d5660f455 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 8666eb566797daa1fbb33775210e638bbcbc5e24..b67eadc1c3710ddf4e8ac6e184dd8c63d1fefeea 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 06b3004fa4f3e89d6eb19d545afe548bfd565e06..d9f9d4abaec00335abe80de26419aef676b0b076 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/0909-Reduce-allocation-of-Vec3D-by-entity-tracker.patch b/patches/server/0909-Reduce-allocation-of-Vec3D-by-entity-tracker.patch deleted file mode 100644 index 2d8a23a3c4..0000000000 --- a/patches/server/0909-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 1c76e0d54320c3aa358159a1590d4701d4f18e9e..e9b585387f6cbc454e7b16feb36a256e733c5488 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1566,10 +1566,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 12d5af9dc6e5d5ed4ea427384226dc5d022550ba..ce3e359ed2b29674aa89a714ee1fb0875d83595d 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/0910-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch b/patches/server/0910-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch deleted file mode 100644 index fe27657709..0000000000 --- a/patches/server/0910-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 5ea56c6048a356d84472ef0e744af41fe063ccc7..3c037cabd8331eb96a6523b37abab4e73ab79a02 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 5c1f2496f3d4123f6e69239820dd759db0af420e..54c43acb3c401a9b616f4d1b871d7c4d5660f455 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 8666eb566797daa1fbb33775210e638bbcbc5e24..b67eadc1c3710ddf4e8ac6e184dd8c63d1fefeea 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 06b3004fa4f3e89d6eb19d545afe548bfd565e06..d9f9d4abaec00335abe80de26419aef676b0b076 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/0910-Add-ShulkerDuplicateEvent.patch b/patches/server/0910-Add-ShulkerDuplicateEvent.patch new file mode 100644 index 0000000000..bba3132bf6 --- /dev/null +++ b/patches/server/0910-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 5e6b66a12af7618fd55b4e32577d718849008b19..64d99b8b576212f754bd316343562b1ba7f604fa 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 5e6b66a12af7618fd55b4e32577d718849008b19..64d99b8b576212f754bd316343562b1ba7f604fa 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 066d8f0592fa4fc9886eab7ca1ba1151b3748b95..44abd5742f2682b6224d6de90d52312000d20429 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -637,6 +637,18 @@ 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); ++ if (eggItem != null) { ++ throw new UnsupportedOperationException("Not yet implemented"); ++ } ++ return eggItem == null ? null : org.bukkit.Color.fromRGB(1); // TODO ++ } ++ // Paper end - spawn egg color visibility ++ + /** + * This helper class represents the different NBT Tags. + *

diff --git a/patches/server/0912-Add-Lifecycle-Event-system.patch b/patches/server/0912-Add-Lifecycle-Event-system.patch new file mode 100644 index 0000000000..c6d462c4f3 --- /dev/null +++ b/patches/server/0912-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 eaea08530ca864158a2fa15dca38ca0c25a49bde..b4a823a62d7088262b7f799c977aec71f8778ff5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1062,6 +1062,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 44abd5742f2682b6224d6de90d52312000d20429..0debfd0f95c063566280556dbd755c717e3aa266 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -649,6 +649,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/0912-Add-api-for-spawn-egg-texture-colors.patch b/patches/server/0912-Add-api-for-spawn-egg-texture-colors.patch deleted file mode 100644 index e75dc4c961..0000000000 --- a/patches/server/0912-Add-api-for-spawn-egg-texture-colors.patch +++ /dev/null @@ -1,29 +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 066d8f0592fa4fc9886eab7ca1ba1151b3748b95..44abd5742f2682b6224d6de90d52312000d20429 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -637,6 +637,18 @@ 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); -+ if (eggItem != null) { -+ throw new UnsupportedOperationException("Not yet implemented"); -+ } -+ return eggItem == null ? null : org.bukkit.Color.fromRGB(1); // TODO -+ } -+ // Paper end - spawn egg color visibility -+ - /** - * This helper class represents the different NBT Tags. - *

diff --git a/patches/server/0913-Add-Lifecycle-Event-system.patch b/patches/server/0913-Add-Lifecycle-Event-system.patch deleted file mode 100644 index c6d462c4f3..0000000000 --- a/patches/server/0913-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 eaea08530ca864158a2fa15dca38ca0c25a49bde..b4a823a62d7088262b7f799c977aec71f8778ff5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1062,6 +1062,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 44abd5742f2682b6224d6de90d52312000d20429..0debfd0f95c063566280556dbd755c717e3aa266 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -649,6 +649,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/0913-ItemStack-Tooltip-API.patch b/patches/server/0913-ItemStack-Tooltip-API.patch new file mode 100644 index 0000000000..3f3d1ceb3a --- /dev/null +++ b/patches/server/0913-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 0debfd0f95c063566280556dbd755c717e3aa266..0e2d9de778e9747d0c2ab897d36c623d2ffbeb95 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -635,6 +635,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/0914-Add-getChunkSnapshot-includeLightData-parameter.patch b/patches/server/0914-Add-getChunkSnapshot-includeLightData-parameter.patch new file mode 100644 index 0000000000..750a593b62 --- /dev/null +++ b/patches/server/0914-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 08956b81b9a3e5caf3adce6699149491ff190d90..bfc8b87941578e8f52f7cd9035776b7db5ab2221 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/0914-ItemStack-Tooltip-API.patch b/patches/server/0914-ItemStack-Tooltip-API.patch deleted file mode 100644 index 3f3d1ceb3a..0000000000 --- a/patches/server/0914-ItemStack-Tooltip-API.patch +++ /dev/null @@ -1,30 +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 0debfd0f95c063566280556dbd755c717e3aa266..0e2d9de778e9747d0c2ab897d36c623d2ffbeb95 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -635,6 +635,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/0915-Add-FluidState-API.patch b/patches/server/0915-Add-FluidState-API.patch new file mode 100644 index 0000000000..e1e2fe004f --- /dev/null +++ b/patches/server/0915-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/0915-Add-getChunkSnapshot-includeLightData-parameter.patch b/patches/server/0915-Add-getChunkSnapshot-includeLightData-parameter.patch deleted file mode 100644 index 750a593b62..0000000000 --- a/patches/server/0915-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 08956b81b9a3e5caf3adce6699149491ff190d90..bfc8b87941578e8f52f7cd9035776b7db5ab2221 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/0916-Add-FluidState-API.patch b/patches/server/0916-Add-FluidState-API.patch deleted file mode 100644 index e1e2fe004f..0000000000 --- a/patches/server/0916-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/0916-add-number-format-api.patch b/patches/server/0916-add-number-format-api.patch new file mode 100644 index 0000000000..d412b5f929 --- /dev/null +++ b/patches/server/0916-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/0917-add-number-format-api.patch b/patches/server/0917-add-number-format-api.patch deleted file mode 100644 index d412b5f929..0000000000 --- a/patches/server/0917-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/0917-improve-BanList-types.patch b/patches/server/0917-improve-BanList-types.patch new file mode 100644 index 0000000000..bb669a58a1 --- /dev/null +++ b/patches/server/0917-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 b4a823a62d7088262b7f799c977aec71f8778ff5..0d62694e2f9086702eaca7a11799eb90a06ce853 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -2272,6 +2272,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/0918-Expanded-Hopper-API.patch b/patches/server/0918-Expanded-Hopper-API.patch new file mode 100644 index 0000000000..2b59ac9974 --- /dev/null +++ b/patches/server/0918-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/0918-improve-BanList-types.patch b/patches/server/0918-improve-BanList-types.patch deleted file mode 100644 index bb669a58a1..0000000000 --- a/patches/server/0918-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 b4a823a62d7088262b7f799c977aec71f8778ff5..0d62694e2f9086702eaca7a11799eb90a06ce853 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -2272,6 +2272,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/0919-Add-BlockBreakProgressUpdateEvent.patch b/patches/server/0919-Add-BlockBreakProgressUpdateEvent.patch new file mode 100644 index 0000000000..396e5e799f --- /dev/null +++ b/patches/server/0919-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 48566fa87db695517214e17b560c84d78f0130bf..2b934a8212b71d60303f3f24b3ce4a5074a9ebab 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1291,6 +1291,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/0919-Expanded-Hopper-API.patch b/patches/server/0919-Expanded-Hopper-API.patch deleted file mode 100644 index 2b59ac9974..0000000000 --- a/patches/server/0919-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/0920-Add-BlockBreakProgressUpdateEvent.patch b/patches/server/0920-Add-BlockBreakProgressUpdateEvent.patch deleted file mode 100644 index f6e72fda26..0000000000 --- a/patches/server/0920-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 97f1722ed5566dcb8c7e0ccdefea1f89574eb12e..c78014bc2a8197d7f57cb652eb2ae4610073aa19 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1291,6 +1291,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/0920-Deprecate-ItemStack-setType.patch b/patches/server/0920-Deprecate-ItemStack-setType.patch new file mode 100644 index 0000000000..e58b22013f --- /dev/null +++ b/patches/server/0920-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/0921-Add-CartographyItemEvent.patch b/patches/server/0921-Add-CartographyItemEvent.patch new file mode 100644 index 0000000000..6288c2ac9e --- /dev/null +++ b/patches/server/0921-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 c442743e70e1985dc596ba948fa97f0475a4c11e..367df4b4bc9506469c68fcab2ef196d88abf7f97 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -3198,6 +3198,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/0921-Deprecate-ItemStack-setType.patch b/patches/server/0921-Deprecate-ItemStack-setType.patch deleted file mode 100644 index e58b22013f..0000000000 --- a/patches/server/0921-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/0922-Add-CartographyItemEvent.patch b/patches/server/0922-Add-CartographyItemEvent.patch deleted file mode 100644 index 6288c2ac9e..0000000000 --- a/patches/server/0922-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 c442743e70e1985dc596ba948fa97f0475a4c11e..367df4b4bc9506469c68fcab2ef196d88abf7f97 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3198,6 +3198,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/0922-More-Raid-API.patch b/patches/server/0922-More-Raid-API.patch new file mode 100644 index 0000000000..dacd8f6bc9 --- /dev/null +++ b/patches/server/0922-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 6689656098a83d5fe39762caaa6d4924249968ce..dc03536264a7e529957736ab040fe4966280b87e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -2311,6 +2311,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/0923-Add-onboarding-message-for-initial-server-start.patch b/patches/server/0923-Add-onboarding-message-for-initial-server-start.patch new file mode 100644 index 0000000000..63a50b5690 --- /dev/null +++ b/patches/server/0923-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 007e01d329a31acf7f4ed4c6dc4de7ad54ccad04..8cf720f08514e8e4f62f4ad196f1277bd761c6b2 100644 +--- a/src/main/java/io/papermc/paper/configuration/Configurations.java ++++ b/src/main/java/io/papermc/paper/configuration/Configurations.java +@@ -127,6 +127,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 d8db428f06606c16466d39cceb2a5e02eb3d3b24..2d2ff826354670fef356e241d939080c9ed3fd4a 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 4555f7f59d15a1f84c0cf76f77a6685fadd48f8c..60883d019ceef9e2430e9416c8b321165bba4fe6 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1148,6 +1148,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/0923-More-Raid-API.patch b/patches/server/0923-More-Raid-API.patch deleted file mode 100644 index dacd8f6bc9..0000000000 --- a/patches/server/0923-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 6689656098a83d5fe39762caaa6d4924249968ce..dc03536264a7e529957736ab040fe4966280b87e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2311,6 +2311,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/0924-Add-onboarding-message-for-initial-server-start.patch b/patches/server/0924-Add-onboarding-message-for-initial-server-start.patch deleted file mode 100644 index 63a50b5690..0000000000 --- a/patches/server/0924-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 007e01d329a31acf7f4ed4c6dc4de7ad54ccad04..8cf720f08514e8e4f62f4ad196f1277bd761c6b2 100644 ---- a/src/main/java/io/papermc/paper/configuration/Configurations.java -+++ b/src/main/java/io/papermc/paper/configuration/Configurations.java -@@ -127,6 +127,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 d8db428f06606c16466d39cceb2a5e02eb3d3b24..2d2ff826354670fef356e241d939080c9ed3fd4a 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 4555f7f59d15a1f84c0cf76f77a6685fadd48f8c..60883d019ceef9e2430e9416c8b321165bba4fe6 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1148,6 +1148,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/0924-Configurable-max-block-fluid-ticks.patch b/patches/server/0924-Configurable-max-block-fluid-ticks.patch new file mode 100644 index 0000000000..4a935d8cb6 --- /dev/null +++ b/patches/server/0924-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 2b934a8212b71d60303f3f24b3ce4a5074a9ebab..dce6f7e23219f655a1085cc0aa33c31aeb5ce139 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -495,9 +495,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/0925-Configurable-max-block-fluid-ticks.patch b/patches/server/0925-Configurable-max-block-fluid-ticks.patch deleted file mode 100644 index 018b1a92a1..0000000000 --- a/patches/server/0925-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 c78014bc2a8197d7f57cb652eb2ae4610073aa19..fbe3836f54245378b46fe2679cd30e68d05fa749 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -495,9 +495,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/0925-Fix-bees-aging-inside-hives.patch b/patches/server/0925-Fix-bees-aging-inside-hives.patch new file mode 100644 index 0000000000..6d5756bd43 --- /dev/null +++ b/patches/server/0925-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 039e42aa243136234009217a5232900d31037de6..65a85b4a4e159cfe55e435ed342a87bcc07b21d5 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 +@@ -310,7 +310,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 + } + } +@@ -470,15 +470,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/0926-Disable-memory-reserve-allocating.patch b/patches/server/0926-Disable-memory-reserve-allocating.patch new file mode 100644 index 0000000000..ea801f5092 --- /dev/null +++ b/patches/server/0926-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/0926-Fix-bees-aging-inside-hives.patch b/patches/server/0926-Fix-bees-aging-inside-hives.patch deleted file mode 100644 index 6d5756bd43..0000000000 --- a/patches/server/0926-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 039e42aa243136234009217a5232900d31037de6..65a85b4a4e159cfe55e435ed342a87bcc07b21d5 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 -@@ -310,7 +310,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 - } - } -@@ -470,15 +470,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/0927-Disable-memory-reserve-allocating.patch b/patches/server/0927-Disable-memory-reserve-allocating.patch deleted file mode 100644 index ea801f5092..0000000000 --- a/patches/server/0927-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/0927-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch b/patches/server/0927-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch new file mode 100644 index 0000000000..3cf04503d8 --- /dev/null +++ b/patches/server/0927-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/0928-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch b/patches/server/0928-Fire-EntityDamageByEntityEvent-for-unowned-wither-sk.patch deleted file mode 100644 index 3cf04503d8..0000000000 --- a/patches/server/0928-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/0928-Fix-DamageSource-API.patch b/patches/server/0928-Fix-DamageSource-API.patch new file mode 100644 index 0000000000..ffb2fb917d --- /dev/null +++ b/patches/server/0928-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 16e3554ae5e729f5e561a95156a27dcdbf97e141..2f3c02b2bd44a97773dc410483d6bf761fe5fe80 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3419,7 +3419,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 ea4e1bf4bfe003c102ecce5958131aa86ec83864..937ed4e77739ff02ff1e4405047f15eac40906fe 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/0929-Fix-DamageSource-API.patch b/patches/server/0929-Fix-DamageSource-API.patch deleted file mode 100644 index 7cffc77010..0000000000 --- a/patches/server/0929-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 c5724826fade3ade6fea3d4f6173b46fdeaf9679..cd0c72dbf026630eae7d479f532c5de7b0606988 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3419,7 +3419,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 ea4e1bf4bfe003c102ecce5958131aa86ec83864..937ed4e77739ff02ff1e4405047f15eac40906fe 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/0929-Fix-creation-of-invalid-block-entity-during-world-ge.patch b/patches/server/0929-Fix-creation-of-invalid-block-entity-during-world-ge.patch new file mode 100644 index 0000000000..ce119a2b69 --- /dev/null +++ b/patches/server/0929-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 b6fb9014d0e4de35b0f5a7e9e99f9db7ec89edcd..e431c66d4cb63ac9654c2575ed23d65e82a0d849 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -996,9 +996,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/0930-Fix-creation-of-invalid-block-entity-during-world-ge.patch b/patches/server/0930-Fix-creation-of-invalid-block-entity-during-world-ge.patch deleted file mode 100644 index ce119a2b69..0000000000 --- a/patches/server/0930-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 b6fb9014d0e4de35b0f5a7e9e99f9db7ec89edcd..e431c66d4cb63ac9654c2575ed23d65e82a0d849 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -996,9 +996,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/0930-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch b/patches/server/0930-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch new file mode 100644 index 0000000000..52c8009585 --- /dev/null +++ b/patches/server/0930-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch @@ -0,0 +1,306 @@ +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 and NPE 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. + +Furthermore since 1.21.2, the DISPENSER_REGISTRY map doesn't have a default +return value anymore and some dispense behaviors like equippable and +regular items will not have a defined behavior in that map and might throw +a NPE in that case. + +diff --git a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java +index 36180e80dbd681e68c60e097015dad890a48b574..dff30954e4c588ee4cc79d3f6dab6fb456934d65 100644 +--- a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java +@@ -67,7 +67,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior { + stack.grow(1); + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +diff --git a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java +index 39c96f5db6e90a470404c6387fa0c1d5531822e5..8aae1d113e84dfad9f2b6f0bcd203ca6c68bc5ce 100644 +--- a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java +@@ -101,7 +101,7 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior { + if (!dropper && !event.getItem().getType().equals(craftItem.getType())) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(sourceblock, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior.getClass() != DefaultDispenseItemBehavior.class) { + idispensebehavior.dispense(sourceblock, eventStack); + } else { +diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +index 5414f05a7a2d9858785d68446f03f2b854799687..e17436e07eaec76e766c94ecdffc8043fbe42340 100644 +--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +@@ -124,7 +124,7 @@ public interface DispenseItemBehavior { + stack.grow(1); + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +@@ -178,7 +178,7 @@ public interface DispenseItemBehavior { + stack.grow(1); + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +@@ -231,8 +231,8 @@ public interface DispenseItemBehavior { + stack.grow(1); + // 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) { ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior ++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { // Paper - fix possible StackOverflowError + idispensebehavior.dispense(pointer, eventStack); + return stack; + } +@@ -282,8 +282,8 @@ public interface DispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // 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) { ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior ++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { // Paper - fix possible StackOverflowError + idispensebehavior.dispense(pointer, eventStack); + return stack; + } +@@ -352,7 +352,7 @@ public interface DispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +@@ -414,7 +414,7 @@ public interface DispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +@@ -452,7 +452,7 @@ public interface DispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +@@ -514,7 +514,7 @@ public interface DispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +@@ -585,7 +585,7 @@ public interface DispenseItemBehavior { + stack.grow(1); + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +@@ -625,7 +625,7 @@ public interface DispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + 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; +@@ -674,7 +674,7 @@ public interface DispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + 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; +@@ -736,7 +736,7 @@ public interface DispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +@@ -818,8 +818,8 @@ public interface DispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // 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) { ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior ++ if (idispensebehavior != DispenseItemBehavior.NOOP && 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..a43ea83dbbd5946096cdde31af766674bda6c3be 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, this) ? 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); +@@ -58,8 +63,8 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior { + stack.grow(1); + // 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) { ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior ++ if (idispensebehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || idispensebehavior != currentBehavior)) { // Paper - fix possible StackOverflowError + idispensebehavior.dispense(pointer, eventStack); + return true; + } +diff --git a/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java +index f2e19218cf0d3b44a617c7d74f782c3e15e3f07f..aae9ec8f3bd39685b37251bef3f9ac846d65c192 100644 +--- a/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java +@@ -87,7 +87,7 @@ public class MinecartDispenseItemBehavior extends DefaultDispenseItemBehavior { + stack.grow(1); + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +diff --git a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java +index 6b343afe473624082e13bee935638eb140271184..baf3feee740c816cf9f0470a8e56a36d02c9a29c 100644 +--- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java +@@ -56,7 +56,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior { + stack.grow(1); + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java +index f5206e4176f58cff4cfe70c94f014afebc98c589..afad4fa3ca1a3186c4569ea073f776dac16817e1 100644 +--- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java +@@ -52,7 +52,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java +index f84987c36a16df19286d6f1badfb1ffb9cc7e770..cc85e96035f7cb2e6493b1cc4748031171d7dbee 100644 +--- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java +@@ -48,7 +48,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior { + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); +- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); ++ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { + idispensebehavior.dispense(pointer, eventStack); + return stack; +diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java +index 6a8e0df7d0150ad8dbbffcd5f49c4623a259e680..84de82e83b885a5c567f45cd90df751f0ef8942a 100644 +--- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java +@@ -116,6 +116,12 @@ public class DispenserBlock extends BaseEntityBlock { + } + } + ++ // Paper start - Fix NPE with equippable and items without behavior ++ public static DispenseItemBehavior getDispenseBehavior(BlockSource pointer, ItemStack stack) { ++ return ((DispenserBlock) pointer.state().getBlock()).getDispenseMethod(pointer.level(), stack); ++ } ++ // Paper end - Fix NPE with equippable and items without behavior ++ + protected DispenseItemBehavior getDispenseMethod(Level world, ItemStack stack) { + if (!stack.isItemEnabled(world.enabledFeatures())) { + return DispenserBlock.DEFAULT_BEHAVIOR; +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 937ed4e77739ff02ff1e4405047f15eac40906fe..41a0650bfd6e72b83364441dd76df3d561d3163e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -2232,7 +2232,7 @@ public class CraftEventFactory { + 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()); ++ net.minecraft.core.dispenser.DispenseItemBehavior itemBehavior = net.minecraft.world.level.block.DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior + if (itemBehavior != net.minecraft.core.dispenser.DispenseItemBehavior.NOOP && itemBehavior != instance) { + itemBehavior.dispense(pointer, eventStack); + return itemStack; diff --git a/patches/server/0931-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch b/patches/server/0931-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch deleted file mode 100644 index 52c8009585..0000000000 --- a/patches/server/0931-Fix-possible-StackOverflowError-and-NPE-for-some-dis.patch +++ /dev/null @@ -1,306 +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 and NPE 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. - -Furthermore since 1.21.2, the DISPENSER_REGISTRY map doesn't have a default -return value anymore and some dispense behaviors like equippable and -regular items will not have a defined behavior in that map and might throw -a NPE in that case. - -diff --git a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java -index 36180e80dbd681e68c60e097015dad890a48b574..dff30954e4c588ee4cc79d3f6dab6fb456934d65 100644 ---- a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java -@@ -67,7 +67,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior { - stack.grow(1); - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -diff --git a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -index 39c96f5db6e90a470404c6387fa0c1d5531822e5..8aae1d113e84dfad9f2b6f0bcd203ca6c68bc5ce 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -@@ -101,7 +101,7 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior { - if (!dropper && !event.getItem().getType().equals(craftItem.getType())) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(sourceblock, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior.getClass() != DefaultDispenseItemBehavior.class) { - idispensebehavior.dispense(sourceblock, eventStack); - } else { -diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index 5414f05a7a2d9858785d68446f03f2b854799687..e17436e07eaec76e766c94ecdffc8043fbe42340 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -124,7 +124,7 @@ public interface DispenseItemBehavior { - stack.grow(1); - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -@@ -178,7 +178,7 @@ public interface DispenseItemBehavior { - stack.grow(1); - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -@@ -231,8 +231,8 @@ public interface DispenseItemBehavior { - stack.grow(1); - // 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) { -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior -+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { // Paper - fix possible StackOverflowError - idispensebehavior.dispense(pointer, eventStack); - return stack; - } -@@ -282,8 +282,8 @@ public interface DispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // 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) { -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior -+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { // Paper - fix possible StackOverflowError - idispensebehavior.dispense(pointer, eventStack); - return stack; - } -@@ -352,7 +352,7 @@ public interface DispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -@@ -414,7 +414,7 @@ public interface DispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -@@ -452,7 +452,7 @@ public interface DispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -@@ -514,7 +514,7 @@ public interface DispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -@@ -585,7 +585,7 @@ public interface DispenseItemBehavior { - stack.grow(1); - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -@@ -625,7 +625,7 @@ public interface DispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - 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; -@@ -674,7 +674,7 @@ public interface DispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - 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; -@@ -736,7 +736,7 @@ public interface DispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -@@ -818,8 +818,8 @@ public interface DispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // 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) { -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior -+ if (idispensebehavior != DispenseItemBehavior.NOOP && 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..a43ea83dbbd5946096cdde31af766674bda6c3be 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, this) ? 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); -@@ -58,8 +63,8 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior { - stack.grow(1); - // 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) { -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior -+ if (idispensebehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || idispensebehavior != currentBehavior)) { // Paper - fix possible StackOverflowError - idispensebehavior.dispense(pointer, eventStack); - return true; - } -diff --git a/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java -index f2e19218cf0d3b44a617c7d74f782c3e15e3f07f..aae9ec8f3bd39685b37251bef3f9ac846d65c192 100644 ---- a/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java -@@ -87,7 +87,7 @@ public class MinecartDispenseItemBehavior extends DefaultDispenseItemBehavior { - stack.grow(1); - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -diff --git a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -index 6b343afe473624082e13bee935638eb140271184..baf3feee740c816cf9f0470a8e56a36d02c9a29c 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -@@ -56,7 +56,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior { - stack.grow(1); - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -index f5206e4176f58cff4cfe70c94f014afebc98c589..afad4fa3ca1a3186c4569ea073f776dac16817e1 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -@@ -52,7 +52,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -index f84987c36a16df19286d6f1badfb1ffb9cc7e770..cc85e96035f7cb2e6493b1cc4748031171d7dbee 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -@@ -48,7 +48,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior { - if (!event.getItem().equals(craftItem)) { - // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); -- DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem()); -+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) { - idispensebehavior.dispense(pointer, eventStack); - return stack; -diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -index 6a8e0df7d0150ad8dbbffcd5f49c4623a259e680..84de82e83b885a5c567f45cd90df751f0ef8942a 100644 ---- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -@@ -116,6 +116,12 @@ public class DispenserBlock extends BaseEntityBlock { - } - } - -+ // Paper start - Fix NPE with equippable and items without behavior -+ public static DispenseItemBehavior getDispenseBehavior(BlockSource pointer, ItemStack stack) { -+ return ((DispenserBlock) pointer.state().getBlock()).getDispenseMethod(pointer.level(), stack); -+ } -+ // Paper end - Fix NPE with equippable and items without behavior -+ - protected DispenseItemBehavior getDispenseMethod(Level world, ItemStack stack) { - if (!stack.isItemEnabled(world.enabledFeatures())) { - return DispenserBlock.DEFAULT_BEHAVIOR; -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 937ed4e77739ff02ff1e4405047f15eac40906fe..41a0650bfd6e72b83364441dd76df3d561d3163e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -2232,7 +2232,7 @@ public class CraftEventFactory { - 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()); -+ net.minecraft.core.dispenser.DispenseItemBehavior itemBehavior = net.minecraft.world.level.block.DispenserBlock.getDispenseBehavior(pointer, eventStack); // Paper - Fix NPE with equippable and items without behavior - if (itemBehavior != net.minecraft.core.dispenser.DispenseItemBehavior.NOOP && itemBehavior != instance) { - itemBehavior.dispense(pointer, eventStack); - return itemStack; diff --git a/patches/server/0931-Improve-tag-parser-handling.patch b/patches/server/0931-Improve-tag-parser-handling.patch new file mode 100644 index 0000000000..f02da534c5 --- /dev/null +++ b/patches/server/0931-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)); + } +@@ -828,6 +835,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/0932-Improve-tag-parser-handling.patch b/patches/server/0932-Improve-tag-parser-handling.patch deleted file mode 100644 index 6902b54527..0000000000 --- a/patches/server/0932-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)); - } -@@ -828,6 +835,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/0932-Item-Mutation-Fixes.patch b/patches/server/0932-Item-Mutation-Fixes.patch new file mode 100644 index 0000000000..ad85291f0b --- /dev/null +++ b/patches/server/0932-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 e200df7fc90de06d420556711ac67fa94a40d1d2..d82c85ace445d139c1bb96d118060caaec6acffa 100644 +--- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java ++++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java +@@ -219,7 +219,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 +@@ -242,10 +242,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/0933-Item-Mutation-Fixes.patch b/patches/server/0933-Item-Mutation-Fixes.patch deleted file mode 100644 index ad85291f0b..0000000000 --- a/patches/server/0933-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 e200df7fc90de06d420556711ac67fa94a40d1d2..d82c85ace445d139c1bb96d118060caaec6acffa 100644 ---- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -@@ -219,7 +219,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 -@@ -242,10 +242,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/0933-Per-world-ticks-per-spawn-settings.patch b/patches/server/0933-Per-world-ticks-per-spawn-settings.patch new file mode 100644 index 0000000000..1f8b8b243b --- /dev/null +++ b/patches/server/0933-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 bfedc52cf8f0416fa2aaf73f694122b9eed09a4e..98198b6827bb71e53dfaf9d7796f592393d197b0 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/0934-Per-world-ticks-per-spawn-settings.patch b/patches/server/0934-Per-world-ticks-per-spawn-settings.patch deleted file mode 100644 index 1f8b8b243b..0000000000 --- a/patches/server/0934-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 bfedc52cf8f0416fa2aaf73f694122b9eed09a4e..98198b6827bb71e53dfaf9d7796f592393d197b0 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/0934-Properly-track-the-changed-item-from-dispense-events.patch b/patches/server/0934-Properly-track-the-changed-item-from-dispense-events.patch new file mode 100644 index 0000000000..8e7c716f12 --- /dev/null +++ b/patches/server/0934-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 e17436e07eaec76e766c94ecdffc8043fbe42340..56631b08b58aac5801b55d4efc948c6617e812ff 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(worldserver.registryAccess(), 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 baf3feee740c816cf9f0470a8e56a36d02c9a29c..281439e430fb8e587549da783bdd93432f8f957f 100644 +--- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java +@@ -65,7 +65,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior { + + // SPIGOT-7923: Avoid create projectiles with empty item + if (!itemstack1.isEmpty()) { +- Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, itemstack1, enumdirection), worldserver, itemstack1, 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, itemstack1, 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 + iprojectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(pointer.blockEntity()); + } + // itemstack.shrink(1); // CraftBukkit - Handled during event processing +diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java +index cc85e96035f7cb2e6493b1cc4748031171d7dbee..16b435216dc7c6a3f8c1c0f9e2323e6afb3a6cb9 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/0935-Properly-track-the-changed-item-from-dispense-events.patch b/patches/server/0935-Properly-track-the-changed-item-from-dispense-events.patch deleted file mode 100644 index 8e7c716f12..0000000000 --- a/patches/server/0935-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 e17436e07eaec76e766c94ecdffc8043fbe42340..56631b08b58aac5801b55d4efc948c6617e812ff 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(worldserver.registryAccess(), 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 baf3feee740c816cf9f0470a8e56a36d02c9a29c..281439e430fb8e587549da783bdd93432f8f957f 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -@@ -65,7 +65,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior { - - // SPIGOT-7923: Avoid create projectiles with empty item - if (!itemstack1.isEmpty()) { -- Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(worldserver, iposition, itemstack1, enumdirection), worldserver, itemstack1, 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, itemstack1, 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 - iprojectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(pointer.blockEntity()); - } - // itemstack.shrink(1); // CraftBukkit - Handled during event processing -diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -index cc85e96035f7cb2e6493b1cc4748031171d7dbee..16b435216dc7c6a3f8c1c0f9e2323e6afb3a6cb9 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/0935-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/0935-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch new file mode 100644 index 0000000000..8533ebb3e0 --- /dev/null +++ b/patches/server/0935-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 98198b6827bb71e53dfaf9d7796f592393d197b0..db2a4ce54cf1df5c47a0907396deadad4a28dfc7 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -446,6 +446,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 dfb7cb134d1f9bce3d8d17fbf50d9b3309f76078..b8ffe547ad29645b65c3df8bd6ccb7c20985711d 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 537adbef6fdefde170c614aa465b94ff29dfe9f0..1aa69f4a7005242925124c74b8229e6fa7362717 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 cc5be3e8c673409226584328d3e78fccf4ccc2f5..b1101156b281d800f18b25208018722bbecded9f 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) { +@@ -949,6 +949,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); + } +@@ -1052,7 +1058,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/0936-Add-config-for-mobs-immune-to-default-effects.patch b/patches/server/0936-Add-config-for-mobs-immune-to-default-effects.patch new file mode 100644 index 0000000000..0cea399af3 --- /dev/null +++ b/patches/server/0936-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 9fac1c16356ab994462852aeb9c42bf32996bbde..bd9e10f79eaf0d23908229b3ebc2227946a14843 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 +@@ -601,7 +601,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 d2752d424ba13a956e45e82e8b5d1d61fe1f669d..557b4e225688416132281e9b1759d46a9b775ff9 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java +@@ -127,6 +127,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/0936-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/0936-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch deleted file mode 100644 index 8533ebb3e0..0000000000 --- a/patches/server/0936-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch +++ /dev/null @@ -1,171 +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 98198b6827bb71e53dfaf9d7796f592393d197b0..db2a4ce54cf1df5c47a0907396deadad4a28dfc7 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -446,6 +446,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 dfb7cb134d1f9bce3d8d17fbf50d9b3309f76078..b8ffe547ad29645b65c3df8bd6ccb7c20985711d 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 537adbef6fdefde170c614aa465b94ff29dfe9f0..1aa69f4a7005242925124c74b8229e6fa7362717 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 cc5be3e8c673409226584328d3e78fccf4ccc2f5..b1101156b281d800f18b25208018722bbecded9f 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) { -@@ -949,6 +949,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); - } -@@ -1052,7 +1058,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/0937-Add-config-for-mobs-immune-to-default-effects.patch b/patches/server/0937-Add-config-for-mobs-immune-to-default-effects.patch deleted file mode 100644 index 0cea399af3..0000000000 --- a/patches/server/0937-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 9fac1c16356ab994462852aeb9c42bf32996bbde..bd9e10f79eaf0d23908229b3ebc2227946a14843 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 -@@ -601,7 +601,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 d2752d424ba13a956e45e82e8b5d1d61fe1f669d..557b4e225688416132281e9b1759d46a9b775ff9 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -@@ -127,6 +127,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/0937-Deep-clone-nbt-tags-in-PDC.patch b/patches/server/0937-Deep-clone-nbt-tags-in-PDC.patch new file mode 100644 index 0000000000..2d822d6907 --- /dev/null +++ b/patches/server/0937-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 f129d714c1a815f348669dc13a5cd4d360e8ed6a..42d25216cc9d3b931ffc7504ccecc109d57a32d0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -376,7 +376,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; + +@@ -1987,7 +1987,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/0938-Deep-clone-nbt-tags-in-PDC.patch b/patches/server/0938-Deep-clone-nbt-tags-in-PDC.patch deleted file mode 100644 index 2d822d6907..0000000000 --- a/patches/server/0938-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 f129d714c1a815f348669dc13a5cd4d360e8ed6a..42d25216cc9d3b931ffc7504ccecc109d57a32d0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -376,7 +376,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; - -@@ -1987,7 +1987,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/0938-Support-old-UUID-format-for-NBT.patch b/patches/server/0938-Support-old-UUID-format-for-NBT.patch new file mode 100644 index 0000000000..68ff8a5255 --- /dev/null +++ b/patches/server/0938-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/0939-Fix-shield-disable-inconsistency.patch b/patches/server/0939-Fix-shield-disable-inconsistency.patch new file mode 100644 index 0000000000..be86c1bbee --- /dev/null +++ b/patches/server/0939-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 95c2e2d73aefcf7c436fad3066e1fedc7299faa1..5b0dcb27cb862e84478b94184b7a1b97fb2e7501 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -2436,7 +2436,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/0939-Support-old-UUID-format-for-NBT.patch b/patches/server/0939-Support-old-UUID-format-for-NBT.patch deleted file mode 100644 index 68ff8a5255..0000000000 --- a/patches/server/0939-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/0940-Fix-shield-disable-inconsistency.patch b/patches/server/0940-Fix-shield-disable-inconsistency.patch deleted file mode 100644 index be86c1bbee..0000000000 --- a/patches/server/0940-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 95c2e2d73aefcf7c436fad3066e1fedc7299faa1..5b0dcb27cb862e84478b94184b7a1b97fb2e7501 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2436,7 +2436,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/0940-Handle-Large-Packets-disconnecting-client.patch b/patches/server/0940-Handle-Large-Packets-disconnecting-client.patch new file mode 100644 index 0000000000..bb12ac74e3 --- /dev/null +++ b/patches/server/0940-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 c12335bc83d31ec65fe2d7cbe0b084748e670010..b0413be1d8565df1c746102a6900806fe3d12373 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/0941-Fix-ItemFlags.patch b/patches/server/0941-Fix-ItemFlags.patch new file mode 100644 index 0000000000..abcf47b19c --- /dev/null +++ b/patches/server/0941-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 42d25216cc9d3b931ffc7504ccecc109d57a32d0..b9ddf1c75d371258c6ccd39095160469e5b644f2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -277,6 +277,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; +@@ -381,6 +387,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) { +@@ -500,6 +510,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) { +@@ -741,7 +765,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 +@@ -1012,6 +1044,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); +@@ -1102,7 +1143,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 +@@ -1908,6 +1949,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); + } + +@@ -1960,6 +2003,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; + } +@@ -2019,6 +2064,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); +@@ -2163,6 +2216,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 { +@@ -2173,6 +2236,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(); +@@ -2333,6 +2404,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/0941-Handle-Large-Packets-disconnecting-client.patch b/patches/server/0941-Handle-Large-Packets-disconnecting-client.patch deleted file mode 100644 index bb12ac74e3..0000000000 --- a/patches/server/0941-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 c12335bc83d31ec65fe2d7cbe0b084748e670010..b0413be1d8565df1c746102a6900806fe3d12373 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/0942-Fix-ItemFlags.patch b/patches/server/0942-Fix-ItemFlags.patch deleted file mode 100644 index abcf47b19c..0000000000 --- a/patches/server/0942-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 42d25216cc9d3b931ffc7504ccecc109d57a32d0..b9ddf1c75d371258c6ccd39095160469e5b644f2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -277,6 +277,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; -@@ -381,6 +387,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) { -@@ -500,6 +510,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) { -@@ -741,7 +765,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 -@@ -1012,6 +1044,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); -@@ -1102,7 +1143,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 -@@ -1908,6 +1949,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); - } - -@@ -1960,6 +2003,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; - } -@@ -2019,6 +2064,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); -@@ -2163,6 +2216,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 { -@@ -2173,6 +2236,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(); -@@ -2333,6 +2404,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/0942-Fix-damage-modifier-inconsistencies.patch b/patches/server/0942-Fix-damage-modifier-inconsistencies.patch new file mode 100644 index 0000000000..57f6c98116 --- /dev/null +++ b/patches/server/0942-Fix-damage-modifier-inconsistencies.patch @@ -0,0 +1,27 @@ +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 damage modifier inconsistencies + +Affect the falling stalactite damage type where the +reduction is not applied like in Vanilla. +Additionally fix the "is_freezing" damage type tag. + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 41a0650bfd6e72b83364441dd76df3d561d3163e..deba03eb37012c638e08e20cd1c98e9db190c790 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1222,11 +1222,11 @@ public class CraftEventFactory { + Map> modifierFunctions = new EnumMap<>(DamageModifier.class); + modifiers.put(DamageModifier.BASE, rawDamage); + modifierFunctions.put(DamageModifier.BASE, CraftEventFactory.ZERO); +- if (source.is(DamageTypes.FREEZE)) { ++ if (source.is(DamageTypeTags.IS_FREEZING)) { // Paper + 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/0943-Fix-damage-modifier-inconsistencies.patch b/patches/server/0943-Fix-damage-modifier-inconsistencies.patch deleted file mode 100644 index 57f6c98116..0000000000 --- a/patches/server/0943-Fix-damage-modifier-inconsistencies.patch +++ /dev/null @@ -1,27 +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 damage modifier inconsistencies - -Affect the falling stalactite damage type where the -reduction is not applied like in Vanilla. -Additionally fix the "is_freezing" damage type tag. - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 41a0650bfd6e72b83364441dd76df3d561d3163e..deba03eb37012c638e08e20cd1c98e9db190c790 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1222,11 +1222,11 @@ public class CraftEventFactory { - Map> modifierFunctions = new EnumMap<>(DamageModifier.class); - modifiers.put(DamageModifier.BASE, rawDamage); - modifierFunctions.put(DamageModifier.BASE, CraftEventFactory.ZERO); -- if (source.is(DamageTypes.FREEZE)) { -+ if (source.is(DamageTypeTags.IS_FREEZING)) { // Paper - 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/0943-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch b/patches/server/0943-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch new file mode 100644 index 0000000000..7944a47a7b --- /dev/null +++ b/patches/server/0943-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch @@ -0,0 +1,63 @@ +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 5b0dcb27cb862e84478b94184b7a1b97fb2e7501..1bb38e6c6a02839fbe72584e91504dfaca3c46e9 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); +@@ -2498,12 +2500,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/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java +index 4f23e32dd7b21492a6fcf7b8bd9b4d9d9a9297a3..c57fac6b5a17f39699298a58d9d25c12da929e64 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java +@@ -388,7 +388,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder -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 5b0dcb27cb862e84478b94184b7a1b97fb2e7501..1bb38e6c6a02839fbe72584e91504dfaca3c46e9 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); -@@ -2498,12 +2500,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/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -index 4f23e32dd7b21492a6fcf7b8bd9b4d9d9a9297a3..c57fac6b5a17f39699298a58d9d25c12da929e64 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -@@ -388,7 +388,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder +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 b9ddf1c75d371258c6ccd39095160469e5b644f2..2c0a61fd4fbfb07ed3d5d27509b3bc8b51cb0a76 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -393,7 +393,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; + }); +@@ -525,9 +525,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); + }); +@@ -2372,75 +2379,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/0945-Expose-hasColor-to-leather-armor.patch b/patches/server/0945-Expose-hasColor-to-leather-armor.patch new file mode 100644 index 0000000000..9166ad6261 --- /dev/null +++ b/patches/server/0945-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/0945-improve-checking-handled-tags-in-itemmeta.patch b/patches/server/0945-improve-checking-handled-tags-in-itemmeta.patch deleted file mode 100644 index 9ca8bac6e1..0000000000 --- a/patches/server/0945-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 b9ddf1c75d371258c6ccd39095160469e5b644f2..2c0a61fd4fbfb07ed3d5d27509b3bc8b51cb0a76 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -393,7 +393,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; - }); -@@ -525,9 +525,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); - }); -@@ -2372,75 +2379,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/0946-Added-API-to-get-player-ha-proxy-address.patch b/patches/server/0946-Added-API-to-get-player-ha-proxy-address.patch new file mode 100644 index 0000000000..f3ff104890 --- /dev/null +++ b/patches/server/0946-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 b0413be1d8565df1c746102a6900806fe3d12373..ba1078a0c4ae0fbb2e75a017aff5fe1a8f431099 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 6ff46062d6ce6401acdbae8f087075788538802a..3901d53737a04f821c8569fa6b79ee4e624f8729 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/0946-Expose-hasColor-to-leather-armor.patch b/patches/server/0946-Expose-hasColor-to-leather-armor.patch deleted file mode 100644 index 9166ad6261..0000000000 --- a/patches/server/0946-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/0947-Added-API-to-get-player-ha-proxy-address.patch b/patches/server/0947-Added-API-to-get-player-ha-proxy-address.patch deleted file mode 100644 index f3ff104890..0000000000 --- a/patches/server/0947-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 b0413be1d8565df1c746102a6900806fe3d12373..ba1078a0c4ae0fbb2e75a017aff5fe1a8f431099 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 6ff46062d6ce6401acdbae8f087075788538802a..3901d53737a04f821c8569fa6b79ee4e624f8729 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/0947-General-ItemMeta-fixes.patch b/patches/server/0947-General-ItemMeta-fixes.patch new file mode 100644 index 0000000000..4986b0d71d --- /dev/null +++ b/patches/server/0947-General-ItemMeta-fixes.patch @@ -0,0 +1,2168 @@ +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 fd5b6a94693bbbf14be39e63025ebd4c44530e2d..bc973b01fee365541866e386ee117f23cfe7cc3a 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -1379,6 +1379,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 2356fd4bf4edb8a44312f772eeb8399b3a2fa216..92ae1dea58478cb17df8fa5d367bec5c63186ae3 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 +@@ -146,6 +146,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 2c0a61fd4fbfb07ed3d5d27509b3bc8b51cb0a76..ecc68d2f80808c5f96f2de396e4057b481ab662f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -201,9 +201,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); +@@ -310,7 +311,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(); +@@ -345,7 +346,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); + } + +@@ -394,6 +395,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; + }); +@@ -912,7 +918,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()) { +@@ -1043,7 +1049,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); + } + +@@ -1093,7 +1099,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; + } + +@@ -1110,10 +1116,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; + } + +@@ -1150,7 +1154,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 +@@ -1246,6 +1250,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 +@@ -1304,7 +1309,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 + } + } + +@@ -1370,6 +1375,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 { +@@ -1385,6 +1391,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 { +@@ -1439,6 +1446,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Override + public void setEnchantable(Integer data) { ++ Preconditions.checkArgument(data == null || data > 0, "Enchantability must be positive"); // Paper + this.enchantableValue = data; + } + +@@ -1615,6 +1623,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; + } + +@@ -1711,7 +1720,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) { +@@ -1724,6 +1733,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; + } + +@@ -1731,22 +1741,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()) { +@@ -1756,6 +1777,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + iterator.remove(); + continue; + } ++ this.checkAttributeList(); // Paper - moved down + this.attributeModifiers.put(next.getKey(), next.getValue()); + } + } +@@ -1763,13 +1785,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(); + +@@ -1789,7 +1811,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(); + +@@ -1811,7 +1833,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(); +@@ -1820,7 +1842,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(); + +@@ -1860,6 +1882,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; +@@ -1875,19 +1898,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; +@@ -1901,6 +1938,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; + } + +@@ -1933,7 +1971,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)) +@@ -1954,7 +1992,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 +@@ -2007,9 +2045,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; +@@ -2032,7 +2070,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) { +@@ -2199,7 +2237,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); + } + +@@ -2300,7 +2338,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; + } + +@@ -2382,7 +2420,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, +@@ -2458,7 +2496,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..49690dab508b07f9f56b2fb21eeb5f20172b5bd3 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 +@@ -317,6 +317,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + + @Override + public void setCustomName(String customName) { ++ Preconditions.checkArgument(customName == null || customName.length() <= 32767, "Custom name is longer than 32767 characters"); + this.customName = customName; + } + +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 7c07ce8af54c367f7ba1b20a06d0879df6c46d54..1fc7af0f8e32bc7c07e187241d78220e8b017945 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java +@@ -173,4 +173,21 @@ public final class SerializableMeta implements ConfigurationSerializable { + + return result; + } ++ ++ // 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/CraftCustomModelDataComponent.java b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftCustomModelDataComponent.java +index 53de6a9b0e72b8bd519949d2b76efe9c558305c5..09c6d22f83895b734a39732b1ba99acc35b27881 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftCustomModelDataComponent.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftCustomModelDataComponent.java +@@ -67,7 +67,7 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo + + @Override + public void setFlags(List flags) { +- this.handle = new CustomModelData(this.handle.floats(), new ArrayList<>(this.handle.flags()), this.handle.strings(), this.handle.colors()); ++ this.handle = new CustomModelData(this.handle.floats(), List.copyOf(flags), this.handle.strings(), this.handle.colors()); // Paper + } + + @Override +@@ -77,7 +77,7 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo + + @Override + public void setStrings(List strings) { +- this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), new ArrayList<>(this.handle.strings()), this.handle.colors()); ++ this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), List.copyOf(strings), this.handle.colors()); // Paper + } + + @Override +@@ -87,7 +87,7 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo + + @Override + public void setColors(List colors) { +- this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), this.handle.strings(), new ArrayList<>(this.handle.colors())); ++ this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), this.handle.strings(), colors.stream().map(Color::asRGB).toList()); // Paper + } + + @Override +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 eaa7c3b4988bd2b2c76dc32b44a087d88089074b..c3bfd621fdf00d400c1600a294262df60b0cd6a5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java +@@ -172,7 +172,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.assetId(), 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/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/0948-General-ItemMeta-fixes.patch b/patches/server/0948-General-ItemMeta-fixes.patch deleted file mode 100644 index 4986b0d71d..0000000000 --- a/patches/server/0948-General-ItemMeta-fixes.patch +++ /dev/null @@ -1,2168 +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 fd5b6a94693bbbf14be39e63025ebd4c44530e2d..bc973b01fee365541866e386ee117f23cfe7cc3a 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -1379,6 +1379,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 2356fd4bf4edb8a44312f772eeb8399b3a2fa216..92ae1dea58478cb17df8fa5d367bec5c63186ae3 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 -@@ -146,6 +146,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 2c0a61fd4fbfb07ed3d5d27509b3bc8b51cb0a76..ecc68d2f80808c5f96f2de396e4057b481ab662f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -201,9 +201,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); -@@ -310,7 +311,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(); -@@ -345,7 +346,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); - } - -@@ -394,6 +395,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; - }); -@@ -912,7 +918,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()) { -@@ -1043,7 +1049,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); - } - -@@ -1093,7 +1099,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; - } - -@@ -1110,10 +1116,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; - } - -@@ -1150,7 +1154,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 -@@ -1246,6 +1250,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 -@@ -1304,7 +1309,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 - } - } - -@@ -1370,6 +1375,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 { -@@ -1385,6 +1391,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 { -@@ -1439,6 +1446,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Override - public void setEnchantable(Integer data) { -+ Preconditions.checkArgument(data == null || data > 0, "Enchantability must be positive"); // Paper - this.enchantableValue = data; - } - -@@ -1615,6 +1623,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; - } - -@@ -1711,7 +1720,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) { -@@ -1724,6 +1733,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; - } - -@@ -1731,22 +1741,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()) { -@@ -1756,6 +1777,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - iterator.remove(); - continue; - } -+ this.checkAttributeList(); // Paper - moved down - this.attributeModifiers.put(next.getKey(), next.getValue()); - } - } -@@ -1763,13 +1785,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(); - -@@ -1789,7 +1811,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(); - -@@ -1811,7 +1833,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(); -@@ -1820,7 +1842,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(); - -@@ -1860,6 +1882,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; -@@ -1875,19 +1898,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; -@@ -1901,6 +1938,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; - } - -@@ -1933,7 +1971,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)) -@@ -1954,7 +1992,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 -@@ -2007,9 +2045,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; -@@ -2032,7 +2070,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) { -@@ -2199,7 +2237,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); - } - -@@ -2300,7 +2338,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; - } - -@@ -2382,7 +2420,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, -@@ -2458,7 +2496,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..49690dab508b07f9f56b2fb21eeb5f20172b5bd3 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 -@@ -317,6 +317,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - - @Override - public void setCustomName(String customName) { -+ Preconditions.checkArgument(customName == null || customName.length() <= 32767, "Custom name is longer than 32767 characters"); - this.customName = customName; - } - -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 7c07ce8af54c367f7ba1b20a06d0879df6c46d54..1fc7af0f8e32bc7c07e187241d78220e8b017945 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java -@@ -173,4 +173,21 @@ public final class SerializableMeta implements ConfigurationSerializable { - - return result; - } -+ -+ // 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/CraftCustomModelDataComponent.java b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftCustomModelDataComponent.java -index 53de6a9b0e72b8bd519949d2b76efe9c558305c5..09c6d22f83895b734a39732b1ba99acc35b27881 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftCustomModelDataComponent.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftCustomModelDataComponent.java -@@ -67,7 +67,7 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo - - @Override - public void setFlags(List flags) { -- this.handle = new CustomModelData(this.handle.floats(), new ArrayList<>(this.handle.flags()), this.handle.strings(), this.handle.colors()); -+ this.handle = new CustomModelData(this.handle.floats(), List.copyOf(flags), this.handle.strings(), this.handle.colors()); // Paper - } - - @Override -@@ -77,7 +77,7 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo - - @Override - public void setStrings(List strings) { -- this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), new ArrayList<>(this.handle.strings()), this.handle.colors()); -+ this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), List.copyOf(strings), this.handle.colors()); // Paper - } - - @Override -@@ -87,7 +87,7 @@ public final class CraftCustomModelDataComponent implements CustomModelDataCompo - - @Override - public void setColors(List colors) { -- this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), this.handle.strings(), new ArrayList<>(this.handle.colors())); -+ this.handle = new CustomModelData(this.handle.floats(), this.handle.flags(), this.handle.strings(), colors.stream().map(Color::asRGB).toList()); // Paper - } - - @Override -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 eaa7c3b4988bd2b2c76dc32b44a087d88089074b..c3bfd621fdf00d400c1600a294262df60b0cd6a5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java -@@ -172,7 +172,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.assetId(), 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/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/0948-More-Chest-Block-API.patch b/patches/server/0948-More-Chest-Block-API.patch new file mode 100644 index 0000000000..5f4d4bb730 --- /dev/null +++ b/patches/server/0948-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 fba3113a57d718e0a49366b07df74ee056430b37..d3b4965bb0a067dccdb2d83ec0947de24dfb5145 100644 +--- a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java +@@ -78,7 +78,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 fba3113a57d718e0a49366b07df74ee056430b37..d3b4965bb0a067dccdb2d83ec0947de24dfb5145 100644 ---- a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -@@ -78,7 +78,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/0950-Brigadier-based-command-API.patch b/patches/server/0950-Brigadier-based-command-API.patch new file mode 100644 index 0000000000..c50f9ac281 --- /dev/null +++ b/patches/server/0950-Brigadier-based-command-API.patch @@ -0,0 +1,2819 @@ +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