From 74ad522fc5818b84772c7808a27227f4ac84df38 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Wed, 7 Jun 2023 22:25:38 -0700 Subject: [PATCH] Rebase chunk patches --- .../server/0019-Rewrite-chunk-system.patch | 3436 +++++++++++++++-- ...igurable-baby-zombie-movement-speed.patch} | 0 .../0021-New-player-chunk-loader-system.patch | 2367 ------------ ...22-Configurable-fishing-time-ranges.patch} | 0 ...-mobs-to-jump-and-take-water-damage.patch} | 0 ....EMPTY-not-rely-on-the-main-thread-f.patch | 397 -- ...despawn-distances-for-living-entiti.patch} | 0 ...-Allow-for-toggling-of-spawn-chunks.patch} | 0 ...lism-for-neighbour-writing-chunk-sta.patch | 999 ----- ...k-and-tnt-entities-at-the-specified.patch} | 0 ...chunk-load-tasks-that-were-not-sched.patch | 71 - ...ent-crashes-server-lists-and-Mojang.patch} | 0 ...0028-Implement-Paper-VersionChecker.patch} | 0 ...-version-history-to-version-command.patch} | 0 ...load-tasks-as-completed-before-relea.patch | 110 - ...=> 0030-Player-affects-spawning-API.patch} | 0 ...he-whether-region-files-do-not-exist.patch | 119 - ...31-Further-improve-server-tick-loop.patch} | 0 ...32-Only-refresh-abilities-if-needed.patch} | 0 ...API.patch => 0033-Entity-Origin-API.patch} | 0 ...vent-tile-entity-and-entity-crashes.patch} | 0 ...figurable-top-of-nether-void-damage.patch} | 0 ...-before-converting-and-renaming-pla.patch} | 0 ... => 0037-Always-tick-falling-blocks.patch} | 0 ...ch => 0038-Configurable-end-credits.patch} | 0 ...explosions-processing-dead-entities.patch} | 0 ...s.patch => 0040-Optimize-explosions.patch} | 0 ...=> 0041-Disable-explosion-knockback.patch} | 0 ...under.patch => 0042-Disable-thunder.patch} | 0 ....patch => 0043-Disable-ice-and-snow.patch} | 0 ...-Configurable-mob-spawner-tick-rate.patch} | 0 ...5-Implement-PlayerLocaleChangeEvent.patch} | 0 ...patch => 0046-Add-BeaconEffectEvent.patch} | 0 ...igurable-container-update-tick-rate.patch} | 0 ...0048-Use-UserCache-for-player-heads.patch} | 0 ...> 0049-Disable-spigot-tick-limiters.patch} | 0 ...=> 0050-Add-PlayerInitialSpawnEvent.patch} | 0 ...rable-Disabling-Cat-Chest-Detection.patch} | 0 ...2-Ensure-commands-are-not-ran-async.patch} | 0 ...hunks-are-slime-spawn-chunks-toggle.patch} | 0 ...ch => 0054-Expose-server-CommandMap.patch} | 0 ...-informative-in-maxHealth-exception.patch} | 0 ...0056-Player-Tab-List-and-Title-APIs.patch} | 0 ...d-configurable-portal-search-radius.patch} | 0 ...patch => 0058-Add-velocity-warnings.patch} | 0 ...le-inter-world-teleportation-safety.patch} | 0 ... 0060-Add-exception-reporting-event.patch} | 0 ...don-t-need-to-when-cerealising-text.patch} | 0 ...reboards-for-non-players-by-default.patch} | 0 ...orking-with-arrows-stuck-in-living-.patch} | 0 ... => 0064-Complete-resource-pack-API.patch} | 0 ...ding-permissions.yml-before-plugins.patch} | 0 ...low-Reloading-of-Custom-Permissions.patch} | 0 ...h => 0067-Remove-Metadata-on-reload.patch} | 0 ...68-Handle-Item-Meta-Inconsistencies.patch} | 0 ...rable-Non-Player-Arrow-Despawn-Rate.patch} | 0 ...atch => 0070-Add-World-Util-Methods.patch} | 0 ...-Custom-replacement-for-eaten-items.patch} | 0 ...h-absorb-values-and-repair-bad-data.patch} | 0 ...73-Use-a-Shared-Random-for-Entities.patch} | 0 ...e-spawn-chances-for-skeleton-horses.patch} | 0 ...dBounds-and-getBlockState-for-inlin.patch} | 0 ...kPhysicsEvent-if-a-plugin-has-a-lis.patch} | 0 ...ntity-AddTo-RemoveFrom-World-Events.patch} | 0 ...8-Configurable-Chunk-Inhabited-Time.patch} | 0 ...t.patch => 0079-EntityPathfindEvent.patch} | 0 ...gionFileCache-and-make-configurable.patch} | 0 ...-Do-not-load-chunks-for-Pathfinding.patch} | 0 ...082-Add-PlayerUseUnknownEntityEvent.patch} | 0 ...Configurable-Grass-Spread-Tick-Rate.patch} | 0 ...-BlockPlaceEvent-triggering-physics.patch} | 0 ...its.patch => 0085-Optimize-DataBits.patch} | 0 ...illa-per-world-scoreboard-coloring-.patch} | 0 ... 0087-Configurable-Player-Collision.patch} | 0 ...nt-to-allow-plugins-to-handle-clien.patch} | 0 ...> 0089-Configurable-RCON-IP-address.patch} | 0 ...tyRegainHealthEvent-isFastRegen-API.patch} | 0 ...to-configure-frosted_ice-properties.patch} | 0 ...possibility-for-getServer-singleton.patch} | 0 ...tem-frames-performance-and-bug-fixe.patch} | 0 ...API-Replenishable-Lootables-Feature.patch} | 0 ...-scoreboard-teams-to-scoreboard.dat.patch} | 0 ...em-property-for-disabling-watchdoge.patch} | 0 ... 0097-Async-GameProfileCache-saving.patch} | 0 ...-Optional-TNT-doesn-t-move-in-water.patch} | 0 ...-redstone-torch-rapid-clock-removal.patch} | 0 ...h => 0100-Add-server-name-parameter.patch} | 0 ...sounds-to-same-world-if-limiting-ra.patch} | 0 ...locking-on-Network-Manager-creation.patch} | 0 ...-profiles-that-have-no-UUID-and-no-.patch} | 0 ...etting-for-proxy-online-mode-status.patch} | 0 ...timise-BlockState-s-hashCode-equals.patch} | 0 ...nfigurable-packet-in-spam-threshold.patch} | 0 ...7-Configurable-flying-kick-messages.patch} | 0 ...nt.patch => 0108-Add-EntityZapEvent.patch} | 0 ...entity-nbt-data-from-falling-blocks.patch} | 0 ...10-Cache-user-authenticator-threads.patch} | 0 ...-Allow-Reloading-of-Command-Aliases.patch} | 0 ...-Add-source-to-PlayerExpChangeEvent.patch} | 0 ... => 0113-Add-ProjectileCollideEvent.patch} | 0 ...ent-Pathfinding-out-of-World-Border.patch} | 0 ...mize-World.isLoaded-BlockPosition-Z.patch} | 0 ...Bound-Treasure-Maps-to-World-Border.patch} | 0 ...igurable-Cartographer-Treasure-Maps.patch} | 0 ...o-control-if-armour-stands-can-move.patch} | 0 ...=> 0119-String-based-Action-Bar-API.patch} | 0 ...0-Properly-fix-item-duplication-bug.patch} | 0 ...-API-s.patch => 0121-Firework-API-s.patch} | 0 ... 0122-PlayerTeleportEndGatewayEvent.patch} | 0 ...ovide-E-TE-Chunk-count-stat-methods.patch} | 0 ...h => 0124-Enforce-Sync-Player-Saves.patch} | 0 ...low-entities-to-ride-themselves-572.patch} | 0 ...I-for-Reason-Source-Triggering-play.patch} | 0 ...patch => 0127-Cap-Entity-Collisions.patch} | 0 ...-CraftScheduler-Async-Task-Debugger.patch} | 0 ...> 0129-Do-not-let-armorstands-drown.patch} | 0 ...e-async-calls-to-restart-the-server.patch} | 0 ...e-parrots-stay-on-shoulders-despite.patch} | 0 ...-option-to-prevent-player-names-fro.patch} | 0 ...leAppender-for-console-improvements.patch} | 0 ...rable-option-to-disable-creeper-lin.patch} | 0 ....patch => 0135-Item-canEntityPickup.patch} | 0 ...layerPickupItemEvent-setFlyAtPlayer.patch} | 0 ...> 0137-PlayerAttemptPickupItemEvent.patch} | 0 ...profile-lookups-to-worldgen-threads.patch} | 0 ...tch => 0139-Add-UnknownCommandEvent.patch} | 0 ...tch => 0140-Basic-PlayerProfile-API.patch} | 0 ... 0141-Shoulder-Entities-Release-API.patch} | 0 ...patch => 0142-Profile-Lookup-Events.patch} | 0 ...layer-logins-during-server-shutdown.patch} | 0 ...patch => 0144-Entity-fromMobSpawner.patch} | 0 ...5-Improve-the-Saddle-API-for-Horses.patch} | 0 ...plement-ensureServerConversions-API.patch} | 0 ...> 0147-Implement-getI18NDisplayName.patch} | 0 ...=> 0148-ProfileWhitelistVerifyEvent.patch} | 0 ...ch => 0149-Fix-this-stupid-bullshit.patch} | 0 ...atch => 0150-LivingEntity-setKiller.patch} | 0 ...wns-should-honor-nametags-and-leash.patch} | 0 ...mer-when-spawner-event-is-cancelled.patch} | 0 ...a-custom-authentication-servers-dow.patch} | 0 ...-prefixes-using-Log4J-configuration.patch} | 0 ...-Log4J-Configuration-Plugin-Loggers.patch} | 0 ...t.patch => 0156-Add-PlayerJumpEvent.patch} | 0 ...le-ServerboundKeepAlivePacket-async.patch} | 0 ...t-protocol-version-and-virtual-host.patch} | 0 ...t-serverside-behavior-of-keepalives.patch} | 0 ...Effects-only-to-players-who-can-see.patch} | 0 ... => 0161-Add-PlayerArmorChangeEvent.patch} | 0 ...om-being-processed-when-the-player-.patch} | 0 ...3-Fix-MC-117075-TE-Unload-Lag-Spike.patch} | 0 ...-implementations-for-captured-block.patch} | 0 ...get-a-BlockState-without-a-snapshot.patch} | 0 ...patch => 0166-AsyncTabCompleteEvent.patch} | 0 ...=> 0167-PlayerPickupExperienceEvent.patch} | 0 ...-Ability-to-apply-mending-to-XP-API.patch} | 0 ...-PlayerNaturallySpawnCreaturesEvent.patch} | 0 ...Add-setPlayerProfile-API-for-Skulls.patch} | 0 ...patch => 0171-PreCreatureSpawnEvent.patch} | 0 ...> 0172-Fill-Profile-Property-Events.patch} | 0 ...layerAdvancementCriterionGrantEvent.patch} | 0 ...ch => 0174-Add-ArmorStand-Item-Meta.patch} | 0 ...Extend-Player-Interact-cancellation.patch} | 0 ... 0176-Tameable-getOwnerUniqueId-API.patch} | 0 ...-crits-helps-mitigate-hacked-client.patch} | 0 ...e-Explicit-Network-Manager-Flushing.patch} | 0 ...t-extended-PaperServerListPingEvent.patch} | 0 ...-PlayerProfile-in-AsyncPreLoginEven.patch} | 0 ...=> 0181-Player.setPlayerProfile-API.patch} | 0 ...patch => 0182-getPlayerUniqueId-API.patch} | 0 ... 0183-Improved-Async-Task-Scheduler.patch} | 0 ...e-legacy-ping-handler-more-reliable.patch} | 0 ...erverListPingEvent-for-legacy-pings.patch} | 0 ...6-Flag-to-disable-the-channel-limit.patch} | 0 ...-Add-openSign-method-to-HumanEntity.patch} | 0 ...rable-sprint-interruption-on-attack.patch} | 0 ...t.patch => 0189-EndermanEscapeEvent.patch} | 0 ...h => 0190-Enderman.teleportRandomly.patch} | 0 ...191-Block-Enderpearl-Travel-Exploit.patch} | 0 ...d.spawnParticle-API-and-add-Builder.patch} | 0 ...ted-Ice-from-loading-holding-chunks.patch} | 0 ...h => 0194-EndermanAttackPlayerEvent.patch} | 0 ...tch => 0195-WitchConsumePotionEvent.patch} | 0 ...patch => 0196-WitchThrowPotionEvent.patch} | 0 ...tem-entities-with-World.spawnEntity.patch} | 0 ...patch => 0198-WitchReadyPotionEvent.patch} | 0 ...199-ItemStack-getMaxItemUseDuration.patch} | 0 ...ement-EntityTeleportEndGatewayEvent.patch} | 0 ...d-flag-on-cancel-of-Explosion-Event.patch} | 0 ...ch => 0202-Fix-CraftEntity-hashCode.patch} | 0 ...e-Alternative-LootPool-Luck-Formula.patch} | 0 ...ls-when-failing-to-save-player-data.patch} | 0 ...-shield-blocking-delay-configurable.patch} | 0 ...=> 0206-Improve-EntityShootBowEvent.patch} | 0 ...patch => 0207-PlayerReadyArrowEvent.patch} | 0 ...nockbackByEntityEvent-and-EntityPus.patch} | 0 ...patch => 0209-Expand-Explosions-API.patch} | 0 ...vingEntity-Hand-Raised-Item-Use-API.patch} | 0 ...-API.patch => 0211-RangedEntity-API.patch} | 0 ...o-disable-ender-dragon-legacy-check.patch} | 0 ...-Implement-World.getEntity-UUID-API.patch} | 0 ...0214-InventoryCloseEvent-Reason-API.patch} | 0 ...tch => 0215-Vex-get-setSummoner-API.patch} | 0 ...ventory-when-cancelling-PlayerInter.patch} | 0 ...-to-keep-logging-IO-off-main-thread.patch} | 0 ...more-information-to-Entity.toString.patch} | 0 ...ts.patch => 0219-EnderDragon-Events.patch} | 0 ...atch => 0220-PlayerElytraBoostEvent.patch} | 0 ...=> 0221-PlayerLaunchProjectileEvent.patch} | 0 ...0222-Improve-BlockPosition-inlining.patch} | 0 ...-armor-stands-from-doing-entity-loo.patch} | 0 ...-Vanished-players-don-t-have-rights.patch} | 0 ...llow-disabling-armour-stand-ticking.patch} | 0 ...tch => 0226-SkeletonHorse-Additions.patch} | 0 ...n-t-call-getItemMeta-on-hasItemMeta.patch} | 0 ...8-Implement-Expanded-ArmorStand-API.patch} | 0 ...vent.patch => 0229-AnvilDamageEvent.patch} | 0 ...ent.patch => 0230-Add-TNTPrimeEvent.patch} | 0 ...d-make-tab-spam-limits-configurable.patch} | 0 ...s.patch => 0232-Fix-NBT-type-issues.patch} | 0 ...emove-unnecessary-itemmeta-handling.patch} | 0 ...es-option-to-debug-dupe-uuid-issues.patch} | 0 ...d-Early-Warning-Feature-to-WatchDog.patch} | 0 ...6-Use-ConcurrentHashMap-in-JsonList.patch} | 0 ...7-Use-a-Queue-for-Queueing-Commands.patch} | 0 ...le-Entities-from-a-chunk-without-sn.patch} | 0 ...timize-BlockPosition-helper-methods.patch} | 0 ...efault-mob-spawn-range-and-water-an.patch} | 0 ...tch => 0241-Slime-Pathfinder-Events.patch} | 0 ...e-speed-for-water-flowing-over-lava.patch} | 0 ...43-Optimize-CraftBlockData-Creation.patch} | 0 ...tch => 0244-Optimize-MappedRegistry.patch} | 0 ...ch => 0245-Add-PhantomPreSpawnEvent.patch} | 0 ....patch => 0246-Add-More-Creeper-API.patch} | 0 ...=> 0247-Inventory-removeItemAnySlot.patch} | 0 ...oadChunk-int-int-false-load-unconve.patch} | 0 ...ray-tracing-methods-to-LivingEntity.patch} | 0 ...-attack-cooldown-methods-for-Player.patch} | 0 ....patch => 0251-Improve-death-events.patch} | 0 ...w-chests-to-be-placed-with-NBT-data.patch} | 0 ...I.patch => 0253-Mob-Pathfinding-API.patch} | 0 ...for-CanPlaceOn-and-CanDestroy-NBT-v.patch} | 0 ...nt-Mob-AI-Rules-from-Loading-Chunks.patch} | 0 ...ning-from-loading-generating-chunks.patch} | 0 ...t-furnace-cook-speed-multiplier-API.patch} | 0 ...=> 0258-Honor-EntityAgeable.ageLock.patch} | 0 ...le-connection-throttle-kick-message.patch} | 0 ...> 0260-Hook-into-CB-plugin-rewrites.patch} | 0 ....patch => 0261-PreSpawnerSpawnEvent.patch} | 0 ...62-Add-LivingEntity-getTargetEntity.patch} | 0 ...I.patch => 0263-Add-sun-related-API.patch} | 0 ...Turtle-API.patch => 0264-Turtle-API.patch} | 0 ...ator-target-events-and-improve-impl.patch} | 0 ...her-worlds-for-shooter-of-projectil.patch} | 0 ...PI.patch => 0267-Add-more-Witch-API.patch} | 0 ...wned-for-Villager-Aggression-Config.patch} | 0 ...vent-players-from-moving-into-unloa.patch} | 0 ...0-Reset-players-airTicks-on-respawn.patch} | 0 ...after-profile-lookups-if-not-needed.patch} | 0 ...r-Thread-Pool-and-Thread-Priorities.patch} | 0 ...=> 0273-Optimize-World-Time-Updates.patch} | 0 ...tore-custom-InventoryHolder-support.patch} | 0 ...=> 0275-Use-Vanilla-Minecart-Speeds.patch} | 0 ...0276-Fix-SpongeAbsortEvent-handling.patch} | 0 ...-allow-digging-into-unloaded-chunks.patch} | 0 ...ult-permission-message-configurable.patch} | 0 ...revent-rayTrace-from-loading-chunks.patch} | 0 ...-Large-Packets-disconnecting-client.patch} | 0 ...ntity-dismount-during-teleportation.patch} | 0 ...I.patch => 0282-Add-more-Zombie-API.patch} | 0 ...mits.patch => 0283-Book-Size-Limits.patch} | 0 ...0284-Add-PlayerConnectionCloseEvent.patch} | 0 ...revent-Enderman-from-loading-chunks.patch} | 0 ...replace-OfflinePlayer-getLastPlayed.patch} | 0 ...ehicle-tracking-issue-on-disconnect.patch} | 0 ...remove-from-being-called-on-Players.patch} | 0 ...ent.patch => 0289-BlockDestroyEvent.patch} | 0 ... => 0290-Async-command-map-building.patch} | 0 ...0291-Implement-Brigadier-Mojang-API.patch} | 0 ...m-Shapeless-Custom-Crafting-Recipes.patch} | 0 ... 0293-Limit-Client-Sign-length-more.patch} | 0 ...e-Oversized-Tile-Entities-in-chunks.patch} | 0 ...ggleEvent-when-whitelist-is-toggled.patch} | 0 ...=> 0296-Entity-getEntitySpawnReason.patch} | 0 ...tch => 0297-Fire-event-on-GS4-query.patch} | 0 ...98-Implement-PlayerPostRespawnEvent.patch} | 0 ...for-pickupDelay-breaks-picking-up-i.patch} | 0 ...ts.patch => 0300-Server-Tick-Events.patch} | 0 ...301-PlayerDeathEvent-getItemsToKeep.patch} | 0 ...Optimize-Captured-TileEntity-Lookup.patch} | 0 ...API.patch => 0303-Add-Heightmap-API.patch} | 0 ...> 0304-Mob-Spawner-API-Enhancements.patch} | 0 ...-to-changed-postToMainThread-method.patch} | 0 ...-item-frames-are-modified-MC-123450.patch} | 0 ...0307-Implement-CraftBlockSoundGroup.patch} | 0 ...e-Keep-Spawn-Loaded-range-per-world.patch} | 0 ...09-Allow-Saving-of-Oversized-Chunks.patch} | 0 ...10-Expose-the-internal-current-tick.patch} | 0 ...11-Fix-World-isChunkGenerated-calls.patch} | 0 ...te-location-if-we-failed-to-read-it.patch} | 0 ...l-Spawned-mobs-towards-natural-spaw.patch} | 0 ...urable-projectile-relative-velocity.patch} | 0 ...h => 0315-offset-item-frame-ticking.patch} | 0 ...-158900.patch => 0316-Fix-MC-158900.patch} | 0 ...event-consuming-the-wrong-itemstack.patch} | 0 ...8-Dont-send-unnecessary-sign-update.patch} | 0 ...-option-to-disable-pillager-patrols.patch} | 0 ...320-Flat-bedrock-generator-settings.patch} | 0 ...k-loads-when-villagers-try-to-find-.patch} | 0 ...656-Fix-Follow-Range-Initial-Target.patch} | 0 ... 0323-Duplicate-UUID-Resolve-Option.patch} | 0 ...ayerDeathEvent-shouldDropExperience.patch} | 0 ...ading-chunks-checking-hive-position.patch} | 0 ...hunks-from-Hoppers-and-other-things.patch} | 0 ...timise-EntityGetter-getPlayerByUUID.patch} | 0 ...328-Fix-items-not-falling-correctly.patch} | 0 ...ize-call-to-getFluid-for-explosions.patch} | 0 ...-in-stack-not-having-effects-when-d.patch} | 0 ...=> 0331-Entity-Activation-Range-2.0.patch} | 0 ...ement-alternative-item-despawn-rate.patch} | 0 ...=> 0333-Tracking-Range-Improvements.patch} | 0 ...-items-vanishing-through-end-portal.patch} | 0 ...ment-optional-per-player-mob-spawns.patch} | 0 ...et-gravity-in-void.-Fixes-MC-167279.patch} | 0 ...37-Improve-Block-breakNaturally-API.patch} | 0 ...-getChunkAt-calls-for-loaded-chunks.patch} | 0 ...0339-Add-debug-for-sync-chunk-loads.patch} | 0 ...0-Remove-garbage-Java-version-check.patch} | 0 ...tch => 0341-Add-ThrownEggHatchEvent.patch} | 0 ...p-API.patch => 0342-Entity-Jump-API.patch} | 0 ...-to-nerf-pigmen-from-nether-portals.patch} | 0 ... => 0344-Make-the-GUI-graph-fancier.patch} | 0 ...45-add-hand-to-BlockMultiPlaceEvent.patch} | 0 ...ipwire-hook-placement-before-update.patch} | 0 ...o-allow-iron-golems-to-spawn-in-air.patch} | 0 ...chance-of-villager-zombie-infection.patch} | 0 ...tch => 0349-Optimise-Chunk-getFluid.patch} | 0 ...rbose-world-setting-to-false-by-def.patch} | 0 ...Add-tick-times-API-and-mspt-command.patch} | 0 ...52-Expose-MinecraftServer-isRunning.patch} | 0 ...dd-Raw-Byte-ItemStack-Serialization.patch} | 0 ...pawn-settings-and-per-player-option.patch} | 0 ...nections-shouldn-t-hold-up-shutdown.patch} | 0 ...ow-bees-to-load-chunks-for-beehives.patch} | 0 ...PlayerChunkMap-adds-crashing-server.patch} | 0 ...tch => 0358-Don-t-tick-dead-players.patch} | 0 ...-Player-s-shouldn-t-be-able-to-move.patch} | 0 ...timize-Collision-to-not-load-chunks.patch} | 0 ...ove-existing-players-to-world-spawn.patch} | 0 ...alSelector-Goal.Flag-Set-operations.patch} | 0 ...h => 0363-Improved-Watchdog-Support.patch} | 0 ....patch => 0364-Optimize-Pathfinding.patch} | 0 ...5-Reduce-Either-Optional-allocation.patch} | 0 ...-memory-footprint-of-NBTTagCompound.patch} | 0 ...ent-opening-inventories-when-frozen.patch} | 0 ...entity-collision-code-if-not-needed.patch} | 0 ...Implement-Player-Client-Options-API.patch} | 0 ...ayer-is-attempted-to-be-removed-fro.patch} | 0 ...-Broken-behavior-of-PlayerJoinEvent.patch} | 0 ...awn-point-if-spawn-in-unloaded-worl.patch} | 0 ...layerAttackEntityCooldownResetEvent.patch} | 0 ...-fire-BlockFade-on-worldgen-threads.patch} | 0 ...tom-creative-and-insomniac-controls.patch} | 0 ...-duplication-issues-and-teleport-is.patch} | 0 ...patch => 0377-Villager-Restocks-API.patch} | 0 ...ickItem-Packet-and-kick-for-invalid.patch} | 0 ...n.patch => 0379-Expose-game-version.patch} | 0 ...> 0380-Optimize-Voxel-Shape-Merging.patch} | 0 ...per-thread-native-byte-buffer-cache.patch} | 0 ....patch => 0382-misc-debugging-dumps.patch} | 0 ...3-Prevent-teleporting-dead-entities.patch} | 0 ...traces-in-log-messages-crash-report.patch} | 0 ...atch => 0385-Implement-Mob-Goal-API.patch} | 0 ...=> 0386-Add-villager-reputation-API.patch} | 0 ...maximum-exp-value-when-merging-orbs.patch} | 0 ...tch => 0388-ExperienceOrbMergeEvent.patch} | 0 ...-Fix-PotionEffect-ignores-icon-flag.patch} | 0 ...brigadier-child-sorting-performance.patch} | 0 ...API.patch => 0391-Potential-bed-API.patch} | 0 ...ait-for-Async-Tasks-during-shutdown.patch} | 0 ...er-respects-game-and-entity-rules-f.patch} | 0 ...nd-End-Portal-Frames-from-being-des.patch} | 0 ...location-of-Vec3D-by-entity-tracker.patch} | 0 ...> 0396-Ensure-safe-gateway-teleport.patch} | 0 ...-for-console-having-all-permissions.patch} | 0 ...x-villager-trading-demand-MC-163962.patch} | 0 ... => 0399-Maps-shouldn-t-load-chunks.patch} | 0 ...okup-for-Treasure-Maps-Fixes-lag-fr.patch} | 0 ...r-runTaskTimerAsynchronously-Plugin.patch} | 0 ...ton-physics-inconsistency-MC-188840.patch} | 0 ...uping.patch => 0403-Fix-sand-duping.patch} | 0 ...sing-chunks-due-to-integer-overflow.patch} | 0 ...desync-in-playerconnection-causing-.patch} | 0 ...older-method-without-block-snapshot.patch} | 0 ...API.patch => 0407-Improve-Arrow-API.patch} | 0 ...mplement-PlayerRecipeBookClickEvent.patch} | 0 ...-Hide-sync-chunk-writes-behind-flag.patch} | 0 ...0-Add-permission-for-command-blocks.patch} | 0 ...ure-Entity-AABB-s-are-never-invalid.patch} | 0 ...d-Difficulty-Remembering-Difficulty.patch} | 0 ...atch => 0413-Paper-dumpitem-command.patch} | 0 ...Legacy-Component-serialization-size.patch} | 0 ...Optimize-Bit-Operations-by-inlining.patch} | 0 ...Plugin-Tickets-to-API-Chunk-Methods.patch} | 0 ...incremental-chunk-and-player-saving.patch} | 0 ...418-Support-old-UUID-format-for-NBT.patch} | 0 ...p-duplicated-GameProfile-Properties.patch} | 0 ...vert-legacy-attributes-in-Item-Meta.patch} | 0 ...Remove-some-streams-from-structures.patch} | 0 ...rom-classes-related-villager-gossip.patch} | 0 ...0423-Support-components-in-ItemMeta.patch} | 0 ...e-fix-EntityTargetLivingEntityEvent.patch} | 0 ...patch => 0425-Add-entity-liquid-API.patch} | 0 ...date-itemstack-legacy-name-and-lore.patch} | 0 ...wn-player-in-correct-world-on-login.patch} | 0 ...atch => 0428-Add-PrepareResultEvent.patch} | 0 ...-for-portal-on-world-gen-entity-add.patch} | 0 ...e-NetworkManager-Exception-Handling.patch} | 0 ...x-arrows-never-despawning-MC-125757.patch} | 0 ...Vanilla-Command-permission-checking.patch} | 0 ...-5989.patch => 0433-Fix-SPIGOT-5989.patch} | 0 ...-Bukkit-world-container-is-not-used.patch} | 0 ...5885-Unable-to-disable-advancements.patch} | 0 ...taPlayer-leak-due-from-quitting-ear.patch} | 0 ...ix-some-rails-connecting-improperly.patch} | 0 ...stake-in-CB-NBT-int-deserialization.patch} | 0 ...rver-load-chunks-from-newer-version.patch} | 0 ...support.patch => 0440-Brand-support.patch} | 0 ...patch => 0441-Add-setMaxPlayers-API.patch} | 0 ...PickupItemAnimation-to-LivingEntity.patch} | 0 ...h => 0443-Don-t-require-FACING-data.patch} | 0 ...eEvent-not-firing-for-all-use-cases.patch} | 0 ...PI.patch => 0445-Add-moon-phase-API.patch} | 0 ...headless-pistons-from-being-created.patch} | 0 ...ent.patch => 0447-Add-BellRingEvent.patch} | 0 ...dd-zombie-targets-turtle-egg-config.patch} | 0 ...patch => 0449-Buffer-joins-to-world.patch} | 0 ...-Eigencraft-redstone-implementation.patch} | 0 ...s-not-working-in-some-kick-messages.patch} | 0 ...reateEvent-needs-to-know-its-entity.patch} | 0 ...ch => 0453-Fix-CraftTeam-null-check.patch} | 0 ...I.patch => 0454-Add-more-Evoker-API.patch} | 0 ...Add-methods-to-get-translation-keys.patch} | 0 ...te-HoverEvent-from-ItemStack-Entity.patch} | 0 ...ch => 0457-Cache-block-data-strings.patch} | 0 ...rtation-and-cancel-velocity-if-tele.patch} | 0 ...l-open-container-api-to-HumanEntity.patch} | 0 ...aFixerUpper-Rewrite-Rules-on-demand.patch} | 0 ...-capture-to-capture-all-items-added.patch} | 0 ...-Counter-to-allow-plugins-to-use-va.patch} | 0 ...track-plugin-scoreboards-by-default.patch} | 0 ...king.patch => 0464-Entity-isTicking.patch} | 0 ...non-whitelisted-player-when-white-l.patch} | 0 ...-Concurrency-issue-in-ShufflingList.patch} | 0 ...eset-Ender-Crystals-on-Dragon-Spawn.patch} | 0 ...-large-move-vectors-crashing-server.patch} | 0 ...atch => 0469-Optimise-getType-calls.patch} | 0 ....patch => 0470-Villager-resetOffers.patch} | 0 ...ce-order-when-capturing-blockstates.patch} | 0 ...lockpos-allocation-from-pathfinding.patch} | 0 ...em-locations-dropped-from-campfires.patch} | 0 ...tch => 0474-Player-elytra-boost-API.patch} | 0 ...75-Fixed-TileEntityBell-memory-leak.patch} | 0 ...ing-up-when-item-stack-is-empty-in-.patch} | 0 ...Add-getOfflinePlayerIfCached-String.patch} | 0 ...ch => 0478-Add-ignore-discounts-API.patch} | 0 ...Toggle-for-removing-existing-dragon.patch} | 0 ...x-client-lag-on-advancement-loading.patch} | 0 ...> 0481-Item-no-age-no-player-pickup.patch} | 0 ...er-Remove-Streams-Optimized-collect.patch} | 0 ...483-Beacon-API-custom-effect-ranges.patch} | 0 ...tch => 0484-Add-API-for-quit-reason.patch} | 0 ...ng-Trader-spawn-rate-config-options.patch} | 0 ...ch => 0486-Expose-world-spawn-angle.patch} | 0 ...patch => 0487-Add-Destroy-Speed-API.patch} | 0 ...-spawnParticle-x-y-z-precision-loss.patch} | 0 ...89-Add-LivingEntity-clearActiveItem.patch} | 0 ...=> 0490-Add-PlayerItemCooldownEvent.patch} | 0 ...rove-performance-of-the-end-generat.patch} | 0 ...PI.patch => 0492-More-lightning-API.patch} | 0 ...should-not-bypass-cramming-gamerule.patch} | 0 ...-missing-default-perms-for-commands.patch} | 0 ...h => 0495-Add-PlayerShearBlockEvent.patch} | 0 ...ng-zombie-villager-discount-exploit.patch} | 0 ....patch => 0497-Limit-recipe-packets.patch} | 0 ...-CraftSound-backwards-compatibility.patch} | 0 ...499-Player-Chunk-Load-Unload-Events.patch} | 0 ...0-Optimize-Dynamic-get-Missing-Keys.patch} | 0 ...-Expose-LivingEntity-hurt-direction.patch} | 0 ...OBSTRUCTED-reason-to-BedEnterResult.patch} | 0 ...-invalid-ingredient-lists-in-Villag.patch} | 0 ...rTradeEvent-and-PlayerPurchaseEvent.patch} | 0 ...ch => 0505-Implement-TargetHitEvent.patch} | 0 ... 0506-MC-4-Fix-item-position-desync.patch} | 0 ...507-Additional-Block-Material-API-s.patch} | 0 ...tch => 0508-Fix-harming-potion-dupe.patch} | 0 ...get-Material-from-Boats-and-Minecar.patch} | 0 ....patch => 0510-Cache-burn-durations.patch} | 0 ...ob-spawner-spawn-egg-transformation.patch} | 0 ...ix-Not-a-string-Map-Conversion-spam.patch} | 0 ...ment-PlayerFlowerPotManipulateEvent.patch} | 0 ...event-not-being-called-in-adventure.patch} | 0 ...h => 0515-Zombie-API-breaking-doors.patch} | 0 ...516-Fix-nerfed-slime-when-splitting.patch} | 0 ...=> 0517-Add-EntityLoadCrossbowEvent.patch} | 0 ...0518-Added-WorldGameRuleChangeEvent.patch} | 0 ...-Added-ServerResourcesReloadedEvent.patch} | 0 ...d-settings-for-mobs-picking-up-loot.patch} | 0 ...mplemented-BlockFailedDispenseEvent.patch} | 0 ...-Added-PlayerLecternPageChangeEvent.patch} | 0 ...-Added-PlayerLoomPatternSelectEvent.patch} | 0 ...nfigurable-door-breaking-difficulty.patch} | 0 ...ty-commands-shall-not-be-dispatched.patch} | 0 ...I-to-expose-exact-interaction-point.patch} | 0 ...OIs.patch => 0527-Remove-stale-POIs.patch} | 0 ...h => 0528-Fix-villager-boat-exploit.patch} | 0 ...I.patch => 0529-Add-sendOpLevel-API.patch} | 0 ...0530-TODO-Registry-Modification-API.patch} | 0 ...h => 0531-Add-StructuresLocateEvent.patch} | 0 ...-for-requiring-a-player-participant.patch} | 0 ...leHitEvent-call-when-fireballs-dead.patch} | 0 ...nent-with-empty-text-instead-of-thr.patch} | 0 ...535-Make-schedule-command-per-world.patch} | 0 ...536-Configurable-max-leash-distance.patch} | 0 ...537-Implement-BlockPreDispenseEvent.patch} | 0 ...ng-of-PlayerChangeBeaconEffectEvent.patch} | 0 ...e-for-always-placing-the-dragon-egg.patch} | 0 ...-PlayerStonecutterRecipeSelectEvent.patch} | 0 ...eash-variable-to-EntityUnleashEvent.patch} | 0 ...shield-blocking-on-dimension-change.patch} | 0 ...atch => 0543-add-DragonEggFormEvent.patch} | 0 ...Event.patch => 0544-EntityMoveEvent.patch} | 0 ...isable-pathfinding-updates-on-block.patch} | 0 ... 0546-Inline-shift-direction-fields.patch} | 0 ...-adding-items-to-BlockDropItemEvent.patch} | 0 ...inThreadExecutor-to-BukkitScheduler.patch} | 0 ...entity-allow-attribute-registration.patch} | 0 ...ix-dead-slime-setSize-invincibility.patch} | 0 ...pes-should-return-an-immutable-list.patch} | 0 ...port-for-hex-color-codes-in-console.patch} | 0 ...atch => 0553-Expose-Tracked-Players.patch} | 0 ...4-Remove-streams-from-SensorNearest.patch} | 0 ...er-exception-on-empty-JsonList-file.patch} | 0 ...GUI.patch => 0556-Improve-ServerGUI.patch} | 0 ...557-fix-converting-txt-to-json-file.patch} | 0 ...atch => 0558-Add-worldborder-events.patch} | 0 ...=> 0559-added-PlayerNameEntityEvent.patch} | 0 ...grindstones-from-overstacking-items.patch} | 0 ...h => 0561-Add-recipe-to-cook-events.patch} | 0 ...patch => 0562-Add-Block-isValidTool.patch} | 0 ...using-signs-inside-spawn-protection.patch} | 0 ....patch => 0564-Expand-world-key-API.patch} | 0 ...ternative-constructor-for-Rotations.patch} | 0 ...y-API.patch => 0566-Item-Rarity-API.patch} | 0 ...py-TESign-isEditable-from-snapshots.patch} | 0 ...d-item-when-player-has-disconnected.patch} | 0 ...elist-use-configurable-kick-message.patch} | 0 ...gnore-result-of-PlayerEditBookEvent.patch} | 0 ...tch => 0571-Expose-protocol-version.patch} | 0 ...ab-completions-for-brigadier-comman.patch} | 0 ...temConsumeEvent-cancelling-properly.patch} | 0 ...patch => 0574-Add-bypass-host-check.patch} | 0 ...0575-Set-area-affect-cloud-rotation.patch} | 0 ...add-isDeeplySleeping-to-HumanEntity.patch} | 0 ...add-consumeFuel-to-FurnaceBurnEvent.patch} | 0 ...-set-drop-chance-to-EntityEquipment.patch} | 0 ...ix-PigZombieAngerEvent-cancellation.patch} | 0 ...ix-PlayerItemHeldEvent-firing-twice.patch} | 0 ... => 0581-Added-PlayerDeepSleepEvent.patch} | 0 ...ld-API.patch => 0582-More-World-API.patch} | 0 ... 0583-Added-PlayerBedFailEnterEvent.patch} | 0 ...-to-convert-between-Component-and-B.patch} | 0 ...n-acting-as-a-bed-respawn-from-the-.patch} | 0 ...acon-activation-deactivation-events.patch} | 0 ...-RespawnFlags-to-PlayerRespawnEvent.patch} | 0 ...dd-Channel-initialization-listeners.patch} | 0 ...mands-if-tab-completion-is-disabled.patch} | 0 ...> 0590-Add-more-WanderingTrader-API.patch} | 0 ...dd-EntityBlockStorage-clearEntities.patch} | 0 ...ssage-to-PlayerAdvancementDoneEvent.patch} | 0 ...address-to-AsyncPlayerPreLoginEvent.patch} | 0 ...close.patch => 0594-Inventory-close.patch} | 0 ...-in-sunlight-API-for-Phantoms-and-S.patch} | 0 ...=> 0596-Fix-CraftPotionBrewer-cache.patch} | 0 ...atch => 0597-Add-basic-Datapack-API.patch} | 0 ...ment-variable-to-disable-server-gui.patch} | 0 ...itions-to-PlayerGameModeChangeEvent.patch} | 0 ... => 0600-ItemStack-repair-check-API.patch} | 0 ....patch => 0601-More-Enchantment-API.patch} | 0 ...ve-range-check-for-block-placing-up.patch} | 0 ...-and-optimise-world-force-upgrading.patch} | 0 ...PI.patch => 0604-Add-Mob-lookAt-API.patch} | 0 ...0605-Add-Unix-domain-socket-support.patch} | 0 ... => 0606-Add-EntityInsideBlockEvent.patch} | 0 ...07-Attributes-API-for-item-defaults.patch} | 0 ...ause-to-Weather-ThunderChangeEvents.patch} | 0 ...patch => 0609-More-Lidded-Block-API.patch} | 0 ...10-Limit-item-frame-cursors-on-maps.patch} | 0 ... => 0611-Add-PlayerKickEvent-causes.patch} | 0 ...0612-Add-PufferFishStateChangeEvent.patch} | 0 ...erBucketEmptyEvent-result-itemstack.patch} | 0 ...tedContainer-instead-of-ThreadingDe.patch} | 0 ...-to-fix-items-merging-through-walls.patch} | 0 ...h => 0616-Add-BellRevealRaiderEvent.patch} | 0 ... 0617-Fix-invulnerable-end-crystals.patch} | 0 ...18-Add-ElderGuardianAppearanceEvent.patch} | 0 ...0619-Fix-dangerous-end-portal-logic.patch} | 0 ...-Biome-Mob-Lookups-for-Mob-Spawning.patch} | 0 ...-Make-item-validations-configurable.patch} | 0 ...patch => 0622-Line-Of-Sight-Changes.patch} | 0 ... => 0623-add-per-world-spawn-limits.patch} | 0 ...h => 0624-Fix-potions-splash-events.patch} | 0 ... => 0625-Add-more-LimitedRegion-API.patch} | 0 ...layerDropItemEvent-using-wrong-item.patch} | 0 ...=> 0627-Missing-Entity-Behavior-API.patch} | 0 ...ect-for-book-edit-is-called-on-main.patch} | 0 ...of-Block-applyBoneMeal-always-being.patch} | 0 ...tChunkIfLoadedImmediately-in-places.patch} | 0 ...rom-signs-not-firing-command-events.patch} | 0 ...ch => 0632-Adds-PlayerArmSwingEvent.patch} | 0 ...-event-leave-message-not-being-sent.patch} | 0 ...-for-mobs-immune-to-default-effects.patch} | 0 ...correct-message-for-outdated-client.patch} | 0 ...-t-apply-cramming-damage-to-players.patch} | 0 ...d-timings-for-sensors-and-behaviors.patch} | 0 ...-bunch-of-missing-forceDrop-toggles.patch} | 0 ...inger-API.patch => 0639-Stinger-API.patch} | 0 ...cy-issue-with-empty-map-items-in-CB.patch} | 0 ... => 0641-Add-System.out-err-catcher.patch} | 0 ... => 0642-Fix-test-not-bootstrapping.patch} | 0 ...-to-contain-the-source-jars-in-stac.patch} | 0 ...-Improve-boat-collision-performance.patch} | 0 ...AFK-kick-while-watching-end-credits.patch} | 0 ...tch => 0646-Add-PlayerSetSpawnEvent.patch} | 0 ...rs-respect-inventory-max-stack-size.patch} | 0 ...ize-entity-tracker-passenger-checks.patch} | 0 ...-option-for-Piglins-guarding-chests.patch} | 0 ...=> 0650-Added-EntityDamageItemEvent.patch} | 0 ...timize-indirect-passenger-iteration.patch} | 0 ...em-frame-map-cursor-update-interval.patch} | 0 ...Make-EntityUnleashEvent-cancellable.patch} | 0 ...654-Clear-bucket-NBT-after-dispense.patch} | 0 ...arget-without-changing-other-things.patch} | 0 ...ch => 0656-Add-BlockBreakBlockEvent.patch} | 0 ...revent-NBT-copy-in-smithing-recipes.patch} | 0 ...patch => 0658-More-CommandBlock-API.patch} | 0 ...-missing-team-sidebar-display-slots.patch} | 0 ...0660-Add-back-EntityPortalExitEvent.patch} | 0 ...-find-targets-for-lightning-strikes.patch} | 0 ... 0662-Get-entity-default-attributes.patch} | 0 ...d-API.patch => 0663-Left-handed-API.patch} | 0 ...ch => 0664-Add-more-advancement-API.patch} | 0 ...665-Add-ItemFactory-getSpawnEgg-API.patch} | 0 ...tch => 0666-Add-critical-damage-API.patch} | 0 ...0667-Fix-issues-with-mob-conversion.patch} | 0 ...ollidable-methods-to-various-places.patch} | 0 ...-ram-API.patch => 0669-Goat-ram-API.patch} | 0 ...dd-API-for-resetting-a-single-score.patch} | 0 ...1-Add-Raw-Byte-Entity-Serialization.patch} | 0 ...72-Vanilla-command-permission-fixes.patch} | 0 ...logic-for-inventories-on-chunk-unlo.patch} | 0 ...74-Fix-GameProfileCache-concurrency.patch} | 0 ...675-Improve-and-expand-AsyncCatcher.patch} | 0 ...per-mobcaps-and-paper-playermobcaps.patch} | 0 ...tize-ResourceLocation-error-logging.patch} | 0 ...=> 0678-Optimise-general-POI-access.patch} | 0 665 files changed, 3009 insertions(+), 4490 deletions(-) rename patches/server/{0022-Configurable-baby-zombie-movement-speed.patch => 0021-Configurable-baby-zombie-movement-speed.patch} (100%) delete mode 100644 patches/server/0021-New-player-chunk-loader-system.patch rename patches/server/{0024-Configurable-fishing-time-ranges.patch => 0022-Configurable-fishing-time-ranges.patch} (100%) rename patches/server/{0026-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch => 0023-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch} (100%) delete mode 100644 patches/server/0023-Make-ChunkStatus.EMPTY-not-rely-on-the-main-thread-f.patch rename patches/server/{0028-Add-configurable-despawn-distances-for-living-entiti.patch => 0024-Add-configurable-despawn-distances-for-living-entiti.patch} (100%) rename patches/server/{0030-Allow-for-toggling-of-spawn-chunks.patch => 0025-Allow-for-toggling-of-spawn-chunks.patch} (100%) delete mode 100644 patches/server/0025-Increase-parallelism-for-neighbour-writing-chunk-sta.patch rename patches/server/{0032-Drop-falling-block-and-tnt-entities-at-the-specified.patch => 0026-Drop-falling-block-and-tnt-entities-at-the-specified.patch} (100%) delete mode 100644 patches/server/0027-Properly-cancel-chunk-load-tasks-that-were-not-sched.patch rename patches/server/{0033-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch => 0027-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch} (100%) rename patches/server/{0034-Implement-Paper-VersionChecker.patch => 0028-Implement-Paper-VersionChecker.patch} (100%) rename patches/server/{0035-Add-version-history-to-version-command.patch => 0029-Add-version-history-to-version-command.patch} (100%) delete mode 100644 patches/server/0029-Mark-POI-Entity-load-tasks-as-completed-before-relea.patch rename patches/server/{0036-Player-affects-spawning-API.patch => 0030-Player-affects-spawning-API.patch} (100%) delete mode 100644 patches/server/0031-Cache-whether-region-files-do-not-exist.patch rename patches/server/{0037-Further-improve-server-tick-loop.patch => 0031-Further-improve-server-tick-loop.patch} (100%) rename patches/server/{0038-Only-refresh-abilities-if-needed.patch => 0032-Only-refresh-abilities-if-needed.patch} (100%) rename patches/server/{0039-Entity-Origin-API.patch => 0033-Entity-Origin-API.patch} (100%) rename patches/server/{0040-Prevent-tile-entity-and-entity-crashes.patch => 0034-Prevent-tile-entity-and-entity-crashes.patch} (100%) rename patches/server/{0041-Configurable-top-of-nether-void-damage.patch => 0035-Configurable-top-of-nether-void-damage.patch} (100%) rename patches/server/{0042-Check-online-mode-before-converting-and-renaming-pla.patch => 0036-Check-online-mode-before-converting-and-renaming-pla.patch} (100%) rename patches/server/{0043-Always-tick-falling-blocks.patch => 0037-Always-tick-falling-blocks.patch} (100%) rename patches/server/{0044-Configurable-end-credits.patch => 0038-Configurable-end-credits.patch} (100%) rename patches/server/{0045-Fix-lag-from-explosions-processing-dead-entities.patch => 0039-Fix-lag-from-explosions-processing-dead-entities.patch} (100%) rename patches/server/{0046-Optimize-explosions.patch => 0040-Optimize-explosions.patch} (100%) rename patches/server/{0047-Disable-explosion-knockback.patch => 0041-Disable-explosion-knockback.patch} (100%) rename patches/server/{0048-Disable-thunder.patch => 0042-Disable-thunder.patch} (100%) rename patches/server/{0049-Disable-ice-and-snow.patch => 0043-Disable-ice-and-snow.patch} (100%) rename patches/server/{0050-Configurable-mob-spawner-tick-rate.patch => 0044-Configurable-mob-spawner-tick-rate.patch} (100%) rename patches/server/{0051-Implement-PlayerLocaleChangeEvent.patch => 0045-Implement-PlayerLocaleChangeEvent.patch} (100%) rename patches/server/{0052-Add-BeaconEffectEvent.patch => 0046-Add-BeaconEffectEvent.patch} (100%) rename patches/server/{0053-Configurable-container-update-tick-rate.patch => 0047-Configurable-container-update-tick-rate.patch} (100%) rename patches/server/{0054-Use-UserCache-for-player-heads.patch => 0048-Use-UserCache-for-player-heads.patch} (100%) rename patches/server/{0055-Disable-spigot-tick-limiters.patch => 0049-Disable-spigot-tick-limiters.patch} (100%) rename patches/server/{0056-Add-PlayerInitialSpawnEvent.patch => 0050-Add-PlayerInitialSpawnEvent.patch} (100%) rename patches/server/{0057-Configurable-Disabling-Cat-Chest-Detection.patch => 0051-Configurable-Disabling-Cat-Chest-Detection.patch} (100%) rename patches/server/{0058-Ensure-commands-are-not-ran-async.patch => 0052-Ensure-commands-are-not-ran-async.patch} (100%) rename patches/server/{0059-All-chunks-are-slime-spawn-chunks-toggle.patch => 0053-All-chunks-are-slime-spawn-chunks-toggle.patch} (100%) rename patches/server/{0060-Expose-server-CommandMap.patch => 0054-Expose-server-CommandMap.patch} (100%) rename patches/server/{0061-Be-a-bit-more-informative-in-maxHealth-exception.patch => 0055-Be-a-bit-more-informative-in-maxHealth-exception.patch} (100%) rename patches/server/{0062-Player-Tab-List-and-Title-APIs.patch => 0056-Player-Tab-List-and-Title-APIs.patch} (100%) rename patches/server/{0063-Add-configurable-portal-search-radius.patch => 0057-Add-configurable-portal-search-radius.patch} (100%) rename patches/server/{0064-Add-velocity-warnings.patch => 0058-Add-velocity-warnings.patch} (100%) rename patches/server/{0065-Configurable-inter-world-teleportation-safety.patch => 0059-Configurable-inter-world-teleportation-safety.patch} (100%) rename patches/server/{0066-Add-exception-reporting-event.patch => 0060-Add-exception-reporting-event.patch} (100%) rename patches/server/{0067-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch => 0061-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch} (100%) rename patches/server/{0068-Disable-Scoreboards-for-non-players-by-default.patch => 0062-Disable-Scoreboards-for-non-players-by-default.patch} (100%) rename patches/server/{0069-Add-methods-for-working-with-arrows-stuck-in-living-.patch => 0063-Add-methods-for-working-with-arrows-stuck-in-living-.patch} (100%) rename patches/server/{0070-Complete-resource-pack-API.patch => 0064-Complete-resource-pack-API.patch} (100%) rename patches/server/{0071-Default-loading-permissions.yml-before-plugins.patch => 0065-Default-loading-permissions.yml-before-plugins.patch} (100%) rename patches/server/{0072-Allow-Reloading-of-Custom-Permissions.patch => 0066-Allow-Reloading-of-Custom-Permissions.patch} (100%) rename patches/server/{0073-Remove-Metadata-on-reload.patch => 0067-Remove-Metadata-on-reload.patch} (100%) rename patches/server/{0074-Handle-Item-Meta-Inconsistencies.patch => 0068-Handle-Item-Meta-Inconsistencies.patch} (100%) rename patches/server/{0075-Configurable-Non-Player-Arrow-Despawn-Rate.patch => 0069-Configurable-Non-Player-Arrow-Despawn-Rate.patch} (100%) rename patches/server/{0076-Add-World-Util-Methods.patch => 0070-Add-World-Util-Methods.patch} (100%) rename patches/server/{0077-Custom-replacement-for-eaten-items.patch => 0071-Custom-replacement-for-eaten-items.patch} (100%) rename patches/server/{0078-handle-NaN-health-absorb-values-and-repair-bad-data.patch => 0072-handle-NaN-health-absorb-values-and-repair-bad-data.patch} (100%) rename patches/server/{0079-Use-a-Shared-Random-for-Entities.patch => 0073-Use-a-Shared-Random-for-Entities.patch} (100%) rename patches/server/{0080-Configurable-spawn-chances-for-skeleton-horses.patch => 0074-Configurable-spawn-chances-for-skeleton-horses.patch} (100%) rename patches/server/{0081-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch => 0075-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch} (100%) rename patches/server/{0082-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch => 0076-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch} (100%) rename patches/server/{0083-Entity-AddTo-RemoveFrom-World-Events.patch => 0077-Entity-AddTo-RemoveFrom-World-Events.patch} (100%) rename patches/server/{0084-Configurable-Chunk-Inhabited-Time.patch => 0078-Configurable-Chunk-Inhabited-Time.patch} (100%) rename patches/server/{0085-EntityPathfindEvent.patch => 0079-EntityPathfindEvent.patch} (100%) rename patches/server/{0086-Sanitise-RegionFileCache-and-make-configurable.patch => 0080-Sanitise-RegionFileCache-and-make-configurable.patch} (100%) rename patches/server/{0087-Do-not-load-chunks-for-Pathfinding.patch => 0081-Do-not-load-chunks-for-Pathfinding.patch} (100%) rename patches/server/{0088-Add-PlayerUseUnknownEntityEvent.patch => 0082-Add-PlayerUseUnknownEntityEvent.patch} (100%) rename patches/server/{0089-Configurable-Grass-Spread-Tick-Rate.patch => 0083-Configurable-Grass-Spread-Tick-Rate.patch} (100%) rename patches/server/{0090-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch => 0084-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch} (100%) rename patches/server/{0091-Optimize-DataBits.patch => 0085-Optimize-DataBits.patch} (100%) rename patches/server/{0092-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch => 0086-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch} (100%) rename patches/server/{0093-Configurable-Player-Collision.patch => 0087-Configurable-Player-Collision.patch} (100%) rename patches/server/{0094-Add-handshake-event-to-allow-plugins-to-handle-clien.patch => 0088-Add-handshake-event-to-allow-plugins-to-handle-clien.patch} (100%) rename patches/server/{0095-Configurable-RCON-IP-address.patch => 0089-Configurable-RCON-IP-address.patch} (100%) rename patches/server/{0096-EntityRegainHealthEvent-isFastRegen-API.patch => 0090-EntityRegainHealthEvent-isFastRegen-API.patch} (100%) rename patches/server/{0097-Add-ability-to-configure-frosted_ice-properties.patch => 0091-Add-ability-to-configure-frosted_ice-properties.patch} (100%) rename patches/server/{0098-remove-null-possibility-for-getServer-singleton.patch => 0092-remove-null-possibility-for-getServer-singleton.patch} (100%) rename patches/server/{0099-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch => 0093-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch} (100%) rename patches/server/{0100-LootTable-API-Replenishable-Lootables-Feature.patch => 0094-LootTable-API-Replenishable-Lootables-Feature.patch} (100%) rename patches/server/{0101-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch => 0095-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch} (100%) rename patches/server/{0102-System-property-for-disabling-watchdoge.patch => 0096-System-property-for-disabling-watchdoge.patch} (100%) rename patches/server/{0103-Async-GameProfileCache-saving.patch => 0097-Async-GameProfileCache-saving.patch} (100%) rename patches/server/{0104-Optional-TNT-doesn-t-move-in-water.patch => 0098-Optional-TNT-doesn-t-move-in-water.patch} (100%) rename patches/server/{0105-Faster-redstone-torch-rapid-clock-removal.patch => 0099-Faster-redstone-torch-rapid-clock-removal.patch} (100%) rename patches/server/{0106-Add-server-name-parameter.patch => 0100-Add-server-name-parameter.patch} (100%) rename patches/server/{0107-Only-send-global-sounds-to-same-world-if-limiting-ra.patch => 0101-Only-send-global-sounds-to-same-world-if-limiting-ra.patch} (100%) rename patches/server/{0108-Avoid-blocking-on-Network-Manager-creation.patch => 0102-Avoid-blocking-on-Network-Manager-creation.patch} (100%) rename patches/server/{0109-Don-t-lookup-game-profiles-that-have-no-UUID-and-no-.patch => 0103-Don-t-lookup-game-profiles-that-have-no-UUID-and-no-.patch} (100%) rename patches/server/{0110-Add-setting-for-proxy-online-mode-status.patch => 0104-Add-setting-for-proxy-online-mode-status.patch} (100%) rename patches/server/{0111-Optimise-BlockState-s-hashCode-equals.patch => 0105-Optimise-BlockState-s-hashCode-equals.patch} (100%) rename patches/server/{0112-Configurable-packet-in-spam-threshold.patch => 0106-Configurable-packet-in-spam-threshold.patch} (100%) rename patches/server/{0113-Configurable-flying-kick-messages.patch => 0107-Configurable-flying-kick-messages.patch} (100%) rename patches/server/{0114-Add-EntityZapEvent.patch => 0108-Add-EntityZapEvent.patch} (100%) rename patches/server/{0115-Filter-bad-tile-entity-nbt-data-from-falling-blocks.patch => 0109-Filter-bad-tile-entity-nbt-data-from-falling-blocks.patch} (100%) rename patches/server/{0116-Cache-user-authenticator-threads.patch => 0110-Cache-user-authenticator-threads.patch} (100%) rename patches/server/{0117-Allow-Reloading-of-Command-Aliases.patch => 0111-Allow-Reloading-of-Command-Aliases.patch} (100%) rename patches/server/{0118-Add-source-to-PlayerExpChangeEvent.patch => 0112-Add-source-to-PlayerExpChangeEvent.patch} (100%) rename patches/server/{0119-Add-ProjectileCollideEvent.patch => 0113-Add-ProjectileCollideEvent.patch} (100%) rename patches/server/{0120-Prevent-Pathfinding-out-of-World-Border.patch => 0114-Prevent-Pathfinding-out-of-World-Border.patch} (100%) rename patches/server/{0121-Optimize-World.isLoaded-BlockPosition-Z.patch => 0115-Optimize-World.isLoaded-BlockPosition-Z.patch} (100%) rename patches/server/{0122-Bound-Treasure-Maps-to-World-Border.patch => 0116-Bound-Treasure-Maps-to-World-Border.patch} (100%) rename patches/server/{0123-Configurable-Cartographer-Treasure-Maps.patch => 0117-Configurable-Cartographer-Treasure-Maps.patch} (100%) rename patches/server/{0124-Add-API-methods-to-control-if-armour-stands-can-move.patch => 0118-Add-API-methods-to-control-if-armour-stands-can-move.patch} (100%) rename patches/server/{0125-String-based-Action-Bar-API.patch => 0119-String-based-Action-Bar-API.patch} (100%) rename patches/server/{0126-Properly-fix-item-duplication-bug.patch => 0120-Properly-fix-item-duplication-bug.patch} (100%) rename patches/server/{0127-Firework-API-s.patch => 0121-Firework-API-s.patch} (100%) rename patches/server/{0128-PlayerTeleportEndGatewayEvent.patch => 0122-PlayerTeleportEndGatewayEvent.patch} (100%) rename patches/server/{0129-Provide-E-TE-Chunk-count-stat-methods.patch => 0123-Provide-E-TE-Chunk-count-stat-methods.patch} (100%) rename patches/server/{0130-Enforce-Sync-Player-Saves.patch => 0124-Enforce-Sync-Player-Saves.patch} (100%) rename patches/server/{0131-Don-t-allow-entities-to-ride-themselves-572.patch => 0125-Don-t-allow-entities-to-ride-themselves-572.patch} (100%) rename patches/server/{0132-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch => 0126-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch} (100%) rename patches/server/{0133-Cap-Entity-Collisions.patch => 0127-Cap-Entity-Collisions.patch} (100%) rename patches/server/{0134-Remove-CraftScheduler-Async-Task-Debugger.patch => 0128-Remove-CraftScheduler-Async-Task-Debugger.patch} (100%) rename patches/server/{0135-Do-not-let-armorstands-drown.patch => 0129-Do-not-let-armorstands-drown.patch} (100%) rename patches/server/{0136-Properly-handle-async-calls-to-restart-the-server.patch => 0130-Properly-handle-async-calls-to-restart-the-server.patch} (100%) rename patches/server/{0137-Add-option-to-make-parrots-stay-on-shoulders-despite.patch => 0131-Add-option-to-make-parrots-stay-on-shoulders-despite.patch} (100%) rename patches/server/{0138-Add-configuration-option-to-prevent-player-names-fro.patch => 0132-Add-configuration-option-to-prevent-player-names-fro.patch} (100%) rename patches/server/{0139-Use-TerminalConsoleAppender-for-console-improvements.patch => 0133-Use-TerminalConsoleAppender-for-console-improvements.patch} (100%) rename patches/server/{0140-provide-a-configurable-option-to-disable-creeper-lin.patch => 0134-provide-a-configurable-option-to-disable-creeper-lin.patch} (100%) rename patches/server/{0141-Item-canEntityPickup.patch => 0135-Item-canEntityPickup.patch} (100%) rename patches/server/{0142-PlayerPickupItemEvent-setFlyAtPlayer.patch => 0136-PlayerPickupItemEvent-setFlyAtPlayer.patch} (100%) rename patches/server/{0143-PlayerAttemptPickupItemEvent.patch => 0137-PlayerAttemptPickupItemEvent.patch} (100%) rename patches/server/{0144-Do-not-submit-profile-lookups-to-worldgen-threads.patch => 0138-Do-not-submit-profile-lookups-to-worldgen-threads.patch} (100%) rename patches/server/{0145-Add-UnknownCommandEvent.patch => 0139-Add-UnknownCommandEvent.patch} (100%) rename patches/server/{0146-Basic-PlayerProfile-API.patch => 0140-Basic-PlayerProfile-API.patch} (100%) rename patches/server/{0147-Shoulder-Entities-Release-API.patch => 0141-Shoulder-Entities-Release-API.patch} (100%) rename patches/server/{0148-Profile-Lookup-Events.patch => 0142-Profile-Lookup-Events.patch} (100%) rename patches/server/{0149-Block-player-logins-during-server-shutdown.patch => 0143-Block-player-logins-during-server-shutdown.patch} (100%) rename patches/server/{0150-Entity-fromMobSpawner.patch => 0144-Entity-fromMobSpawner.patch} (100%) rename patches/server/{0151-Improve-the-Saddle-API-for-Horses.patch => 0145-Improve-the-Saddle-API-for-Horses.patch} (100%) rename patches/server/{0152-Implement-ensureServerConversions-API.patch => 0146-Implement-ensureServerConversions-API.patch} (100%) rename patches/server/{0153-Implement-getI18NDisplayName.patch => 0147-Implement-getI18NDisplayName.patch} (100%) rename patches/server/{0154-ProfileWhitelistVerifyEvent.patch => 0148-ProfileWhitelistVerifyEvent.patch} (100%) rename patches/server/{0155-Fix-this-stupid-bullshit.patch => 0149-Fix-this-stupid-bullshit.patch} (100%) rename patches/server/{0156-LivingEntity-setKiller.patch => 0150-LivingEntity-setKiller.patch} (100%) rename patches/server/{0157-Ocelot-despawns-should-honor-nametags-and-leash.patch => 0151-Ocelot-despawns-should-honor-nametags-and-leash.patch} (100%) rename patches/server/{0158-Reset-spawner-timer-when-spawner-event-is-cancelled.patch => 0152-Reset-spawner-timer-when-spawner-event-is-cancelled.patch} (100%) rename patches/server/{0159-Allow-specifying-a-custom-authentication-servers-dow.patch => 0153-Allow-specifying-a-custom-authentication-servers-dow.patch} (100%) rename patches/server/{0160-Handle-plugin-prefixes-using-Log4J-configuration.patch => 0154-Handle-plugin-prefixes-using-Log4J-configuration.patch} (100%) rename patches/server/{0161-Improve-Log4J-Configuration-Plugin-Loggers.patch => 0155-Improve-Log4J-Configuration-Plugin-Loggers.patch} (100%) rename patches/server/{0162-Add-PlayerJumpEvent.patch => 0156-Add-PlayerJumpEvent.patch} (100%) rename patches/server/{0163-handle-ServerboundKeepAlivePacket-async.patch => 0157-handle-ServerboundKeepAlivePacket-async.patch} (100%) rename patches/server/{0164-Expose-client-protocol-version-and-virtual-host.patch => 0158-Expose-client-protocol-version-and-virtual-host.patch} (100%) rename patches/server/{0165-revert-serverside-behavior-of-keepalives.patch => 0159-revert-serverside-behavior-of-keepalives.patch} (100%) rename patches/server/{0166-Send-attack-SoundEffects-only-to-players-who-can-see.patch => 0160-Send-attack-SoundEffects-only-to-players-who-can-see.patch} (100%) rename patches/server/{0167-Add-PlayerArmorChangeEvent.patch => 0161-Add-PlayerArmorChangeEvent.patch} (100%) rename patches/server/{0168-Prevent-logins-from-being-processed-when-the-player-.patch => 0162-Prevent-logins-from-being-processed-when-the-player-.patch} (100%) rename patches/server/{0169-Fix-MC-117075-TE-Unload-Lag-Spike.patch => 0163-Fix-MC-117075-TE-Unload-Lag-Spike.patch} (100%) rename patches/server/{0170-use-CB-BlockState-implementations-for-captured-block.patch => 0164-use-CB-BlockState-implementations-for-captured-block.patch} (100%) rename patches/server/{0171-API-to-get-a-BlockState-without-a-snapshot.patch => 0165-API-to-get-a-BlockState-without-a-snapshot.patch} (100%) rename patches/server/{0172-AsyncTabCompleteEvent.patch => 0166-AsyncTabCompleteEvent.patch} (100%) rename patches/server/{0173-PlayerPickupExperienceEvent.patch => 0167-PlayerPickupExperienceEvent.patch} (100%) rename patches/server/{0174-Ability-to-apply-mending-to-XP-API.patch => 0168-Ability-to-apply-mending-to-XP-API.patch} (100%) rename patches/server/{0175-PlayerNaturallySpawnCreaturesEvent.patch => 0169-PlayerNaturallySpawnCreaturesEvent.patch} (100%) rename patches/server/{0176-Add-setPlayerProfile-API-for-Skulls.patch => 0170-Add-setPlayerProfile-API-for-Skulls.patch} (100%) rename patches/server/{0177-PreCreatureSpawnEvent.patch => 0171-PreCreatureSpawnEvent.patch} (100%) rename patches/server/{0178-Fill-Profile-Property-Events.patch => 0172-Fill-Profile-Property-Events.patch} (100%) rename patches/server/{0179-PlayerAdvancementCriterionGrantEvent.patch => 0173-PlayerAdvancementCriterionGrantEvent.patch} (100%) rename patches/server/{0180-Add-ArmorStand-Item-Meta.patch => 0174-Add-ArmorStand-Item-Meta.patch} (100%) rename patches/server/{0181-Extend-Player-Interact-cancellation.patch => 0175-Extend-Player-Interact-cancellation.patch} (100%) rename patches/server/{0182-Tameable-getOwnerUniqueId-API.patch => 0176-Tameable-getOwnerUniqueId-API.patch} (100%) rename patches/server/{0183-Toggleable-player-crits-helps-mitigate-hacked-client.patch => 0177-Toggleable-player-crits-helps-mitigate-hacked-client.patch} (100%) rename patches/server/{0184-Disable-Explicit-Network-Manager-Flushing.patch => 0178-Disable-Explicit-Network-Manager-Flushing.patch} (100%) rename patches/server/{0185-Implement-extended-PaperServerListPingEvent.patch => 0179-Implement-extended-PaperServerListPingEvent.patch} (100%) rename patches/server/{0186-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch => 0180-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch} (100%) rename patches/server/{0187-Player.setPlayerProfile-API.patch => 0181-Player.setPlayerProfile-API.patch} (100%) rename patches/server/{0188-getPlayerUniqueId-API.patch => 0182-getPlayerUniqueId-API.patch} (100%) rename patches/server/{0189-Improved-Async-Task-Scheduler.patch => 0183-Improved-Async-Task-Scheduler.patch} (100%) rename patches/server/{0190-Make-legacy-ping-handler-more-reliable.patch => 0184-Make-legacy-ping-handler-more-reliable.patch} (100%) rename patches/server/{0191-Call-PaperServerListPingEvent-for-legacy-pings.patch => 0185-Call-PaperServerListPingEvent-for-legacy-pings.patch} (100%) rename patches/server/{0192-Flag-to-disable-the-channel-limit.patch => 0186-Flag-to-disable-the-channel-limit.patch} (100%) rename patches/server/{0193-Add-openSign-method-to-HumanEntity.patch => 0187-Add-openSign-method-to-HumanEntity.patch} (100%) rename patches/server/{0194-Configurable-sprint-interruption-on-attack.patch => 0188-Configurable-sprint-interruption-on-attack.patch} (100%) rename patches/server/{0195-EndermanEscapeEvent.patch => 0189-EndermanEscapeEvent.patch} (100%) rename patches/server/{0196-Enderman.teleportRandomly.patch => 0190-Enderman.teleportRandomly.patch} (100%) rename patches/server/{0197-Block-Enderpearl-Travel-Exploit.patch => 0191-Block-Enderpearl-Travel-Exploit.patch} (100%) rename patches/server/{0198-Expand-World.spawnParticle-API-and-add-Builder.patch => 0192-Expand-World.spawnParticle-API-and-add-Builder.patch} (100%) rename patches/server/{0199-Prevent-Frosted-Ice-from-loading-holding-chunks.patch => 0193-Prevent-Frosted-Ice-from-loading-holding-chunks.patch} (100%) rename patches/server/{0200-EndermanAttackPlayerEvent.patch => 0194-EndermanAttackPlayerEvent.patch} (100%) rename patches/server/{0201-WitchConsumePotionEvent.patch => 0195-WitchConsumePotionEvent.patch} (100%) rename patches/server/{0202-WitchThrowPotionEvent.patch => 0196-WitchThrowPotionEvent.patch} (100%) rename patches/server/{0203-Allow-spawning-Item-entities-with-World.spawnEntity.patch => 0197-Allow-spawning-Item-entities-with-World.spawnEntity.patch} (100%) rename patches/server/{0204-WitchReadyPotionEvent.patch => 0198-WitchReadyPotionEvent.patch} (100%) rename patches/server/{0205-ItemStack-getMaxItemUseDuration.patch => 0199-ItemStack-getMaxItemUseDuration.patch} (100%) rename patches/server/{0206-Implement-EntityTeleportEndGatewayEvent.patch => 0200-Implement-EntityTeleportEndGatewayEvent.patch} (100%) rename patches/server/{0207-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch => 0201-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch} (100%) rename patches/server/{0208-Fix-CraftEntity-hashCode.patch => 0202-Fix-CraftEntity-hashCode.patch} (100%) rename patches/server/{0209-Configurable-Alternative-LootPool-Luck-Formula.patch => 0203-Configurable-Alternative-LootPool-Luck-Formula.patch} (100%) rename patches/server/{0210-Print-Error-details-when-failing-to-save-player-data.patch => 0204-Print-Error-details-when-failing-to-save-player-data.patch} (100%) rename patches/server/{0211-Make-shield-blocking-delay-configurable.patch => 0205-Make-shield-blocking-delay-configurable.patch} (100%) rename patches/server/{0212-Improve-EntityShootBowEvent.patch => 0206-Improve-EntityShootBowEvent.patch} (100%) rename patches/server/{0213-PlayerReadyArrowEvent.patch => 0207-PlayerReadyArrowEvent.patch} (100%) rename patches/server/{0214-Implement-EntityKnockbackByEntityEvent-and-EntityPus.patch => 0208-Implement-EntityKnockbackByEntityEvent-and-EntityPus.patch} (100%) rename patches/server/{0215-Expand-Explosions-API.patch => 0209-Expand-Explosions-API.patch} (100%) rename patches/server/{0216-LivingEntity-Hand-Raised-Item-Use-API.patch => 0210-LivingEntity-Hand-Raised-Item-Use-API.patch} (100%) rename patches/server/{0217-RangedEntity-API.patch => 0211-RangedEntity-API.patch} (100%) rename patches/server/{0218-Add-config-to-disable-ender-dragon-legacy-check.patch => 0212-Add-config-to-disable-ender-dragon-legacy-check.patch} (100%) rename patches/server/{0219-Implement-World.getEntity-UUID-API.patch => 0213-Implement-World.getEntity-UUID-API.patch} (100%) rename patches/server/{0220-InventoryCloseEvent-Reason-API.patch => 0214-InventoryCloseEvent-Reason-API.patch} (100%) rename patches/server/{0221-Vex-get-setSummoner-API.patch => 0215-Vex-get-setSummoner-API.patch} (100%) rename patches/server/{0222-Refresh-player-inventory-when-cancelling-PlayerInter.patch => 0216-Refresh-player-inventory-when-cancelling-PlayerInter.patch} (100%) rename patches/server/{0223-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch => 0217-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch} (100%) rename patches/server/{0224-add-more-information-to-Entity.toString.patch => 0218-add-more-information-to-Entity.toString.patch} (100%) rename patches/server/{0225-EnderDragon-Events.patch => 0219-EnderDragon-Events.patch} (100%) rename patches/server/{0226-PlayerElytraBoostEvent.patch => 0220-PlayerElytraBoostEvent.patch} (100%) rename patches/server/{0227-PlayerLaunchProjectileEvent.patch => 0221-PlayerLaunchProjectileEvent.patch} (100%) rename patches/server/{0228-Improve-BlockPosition-inlining.patch => 0222-Improve-BlockPosition-inlining.patch} (100%) rename patches/server/{0229-Option-to-prevent-armor-stands-from-doing-entity-loo.patch => 0223-Option-to-prevent-armor-stands-from-doing-entity-loo.patch} (100%) rename patches/server/{0230-Vanished-players-don-t-have-rights.patch => 0224-Vanished-players-don-t-have-rights.patch} (100%) rename patches/server/{0231-Allow-disabling-armour-stand-ticking.patch => 0225-Allow-disabling-armour-stand-ticking.patch} (100%) rename patches/server/{0232-SkeletonHorse-Additions.patch => 0226-SkeletonHorse-Additions.patch} (100%) rename patches/server/{0233-Don-t-call-getItemMeta-on-hasItemMeta.patch => 0227-Don-t-call-getItemMeta-on-hasItemMeta.patch} (100%) rename patches/server/{0234-Implement-Expanded-ArmorStand-API.patch => 0228-Implement-Expanded-ArmorStand-API.patch} (100%) rename patches/server/{0235-AnvilDamageEvent.patch => 0229-AnvilDamageEvent.patch} (100%) rename patches/server/{0236-Add-TNTPrimeEvent.patch => 0230-Add-TNTPrimeEvent.patch} (100%) rename patches/server/{0237-Break-up-and-make-tab-spam-limits-configurable.patch => 0231-Break-up-and-make-tab-spam-limits-configurable.patch} (100%) rename patches/server/{0238-Fix-NBT-type-issues.patch => 0232-Fix-NBT-type-issues.patch} (100%) rename patches/server/{0239-Remove-unnecessary-itemmeta-handling.patch => 0233-Remove-unnecessary-itemmeta-handling.patch} (100%) rename patches/server/{0240-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch => 0234-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch} (100%) rename patches/server/{0241-Add-Early-Warning-Feature-to-WatchDog.patch => 0235-Add-Early-Warning-Feature-to-WatchDog.patch} (100%) rename patches/server/{0242-Use-ConcurrentHashMap-in-JsonList.patch => 0236-Use-ConcurrentHashMap-in-JsonList.patch} (100%) rename patches/server/{0243-Use-a-Queue-for-Queueing-Commands.patch => 0237-Use-a-Queue-for-Queueing-Commands.patch} (100%) rename patches/server/{0244-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch => 0238-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch} (100%) rename patches/server/{0245-Optimize-BlockPosition-helper-methods.patch => 0239-Optimize-BlockPosition-helper-methods.patch} (100%) rename patches/server/{0246-Restore-vanilla-default-mob-spawn-range-and-water-an.patch => 0240-Restore-vanilla-default-mob-spawn-range-and-water-an.patch} (100%) rename patches/server/{0247-Slime-Pathfinder-Events.patch => 0241-Slime-Pathfinder-Events.patch} (100%) rename patches/server/{0248-Configurable-speed-for-water-flowing-over-lava.patch => 0242-Configurable-speed-for-water-flowing-over-lava.patch} (100%) rename patches/server/{0249-Optimize-CraftBlockData-Creation.patch => 0243-Optimize-CraftBlockData-Creation.patch} (100%) rename patches/server/{0250-Optimize-MappedRegistry.patch => 0244-Optimize-MappedRegistry.patch} (100%) rename patches/server/{0251-Add-PhantomPreSpawnEvent.patch => 0245-Add-PhantomPreSpawnEvent.patch} (100%) rename patches/server/{0252-Add-More-Creeper-API.patch => 0246-Add-More-Creeper-API.patch} (100%) rename patches/server/{0253-Inventory-removeItemAnySlot.patch => 0247-Inventory-removeItemAnySlot.patch} (100%) rename patches/server/{0254-Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch => 0248-Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch} (100%) rename patches/server/{0255-Add-ray-tracing-methods-to-LivingEntity.patch => 0249-Add-ray-tracing-methods-to-LivingEntity.patch} (100%) rename patches/server/{0256-Expose-attack-cooldown-methods-for-Player.patch => 0250-Expose-attack-cooldown-methods-for-Player.patch} (100%) rename patches/server/{0257-Improve-death-events.patch => 0251-Improve-death-events.patch} (100%) rename patches/server/{0258-Allow-chests-to-be-placed-with-NBT-data.patch => 0252-Allow-chests-to-be-placed-with-NBT-data.patch} (100%) rename patches/server/{0259-Mob-Pathfinding-API.patch => 0253-Mob-Pathfinding-API.patch} (100%) rename patches/server/{0260-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch => 0254-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch} (100%) rename patches/server/{0261-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch => 0255-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch} (100%) rename patches/server/{0262-Prevent-mob-spawning-from-loading-generating-chunks.patch => 0256-Prevent-mob-spawning-from-loading-generating-chunks.patch} (100%) rename patches/server/{0263-Implement-furnace-cook-speed-multiplier-API.patch => 0257-Implement-furnace-cook-speed-multiplier-API.patch} (100%) rename patches/server/{0264-Honor-EntityAgeable.ageLock.patch => 0258-Honor-EntityAgeable.ageLock.patch} (100%) rename patches/server/{0265-Configurable-connection-throttle-kick-message.patch => 0259-Configurable-connection-throttle-kick-message.patch} (100%) rename patches/server/{0266-Hook-into-CB-plugin-rewrites.patch => 0260-Hook-into-CB-plugin-rewrites.patch} (100%) rename patches/server/{0267-PreSpawnerSpawnEvent.patch => 0261-PreSpawnerSpawnEvent.patch} (100%) rename patches/server/{0268-Add-LivingEntity-getTargetEntity.patch => 0262-Add-LivingEntity-getTargetEntity.patch} (100%) rename patches/server/{0269-Add-sun-related-API.patch => 0263-Add-sun-related-API.patch} (100%) rename patches/server/{0270-Turtle-API.patch => 0264-Turtle-API.patch} (100%) rename patches/server/{0271-Call-player-spectator-target-events-and-improve-impl.patch => 0265-Call-player-spectator-target-events-and-improve-impl.patch} (100%) rename patches/server/{0272-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch => 0266-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch} (100%) rename patches/server/{0273-Add-more-Witch-API.patch => 0267-Add-more-Witch-API.patch} (100%) rename patches/server/{0274-Check-Drowned-for-Villager-Aggression-Config.patch => 0268-Check-Drowned-for-Villager-Aggression-Config.patch} (100%) rename patches/server/{0275-Add-option-to-prevent-players-from-moving-into-unloa.patch => 0269-Add-option-to-prevent-players-from-moving-into-unloa.patch} (100%) rename patches/server/{0276-Reset-players-airTicks-on-respawn.patch => 0270-Reset-players-airTicks-on-respawn.patch} (100%) rename patches/server/{0277-Don-t-sleep-after-profile-lookups-if-not-needed.patch => 0271-Don-t-sleep-after-profile-lookups-if-not-needed.patch} (100%) rename patches/server/{0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch => 0272-Improve-Server-Thread-Pool-and-Thread-Priorities.patch} (100%) rename patches/server/{0279-Optimize-World-Time-Updates.patch => 0273-Optimize-World-Time-Updates.patch} (100%) rename patches/server/{0280-Restore-custom-InventoryHolder-support.patch => 0274-Restore-custom-InventoryHolder-support.patch} (100%) rename patches/server/{0281-Use-Vanilla-Minecart-Speeds.patch => 0275-Use-Vanilla-Minecart-Speeds.patch} (100%) rename patches/server/{0282-Fix-SpongeAbsortEvent-handling.patch => 0276-Fix-SpongeAbsortEvent-handling.patch} (100%) rename patches/server/{0283-Don-t-allow-digging-into-unloaded-chunks.patch => 0277-Don-t-allow-digging-into-unloaded-chunks.patch} (100%) rename patches/server/{0284-Make-the-default-permission-message-configurable.patch => 0278-Make-the-default-permission-message-configurable.patch} (100%) rename patches/server/{0285-Prevent-rayTrace-from-loading-chunks.patch => 0279-Prevent-rayTrace-from-loading-chunks.patch} (100%) rename patches/server/{0286-Handle-Large-Packets-disconnecting-client.patch => 0280-Handle-Large-Packets-disconnecting-client.patch} (100%) rename patches/server/{0287-force-entity-dismount-during-teleportation.patch => 0281-force-entity-dismount-during-teleportation.patch} (100%) rename patches/server/{0288-Add-more-Zombie-API.patch => 0282-Add-more-Zombie-API.patch} (100%) rename patches/server/{0289-Book-Size-Limits.patch => 0283-Book-Size-Limits.patch} (100%) rename patches/server/{0290-Add-PlayerConnectionCloseEvent.patch => 0284-Add-PlayerConnectionCloseEvent.patch} (100%) rename patches/server/{0291-Prevent-Enderman-from-loading-chunks.patch => 0285-Prevent-Enderman-from-loading-chunks.patch} (100%) rename patches/server/{0292-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch => 0286-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch} (100%) rename patches/server/{0293-Workaround-for-vehicle-tracking-issue-on-disconnect.patch => 0287-Workaround-for-vehicle-tracking-issue-on-disconnect.patch} (100%) rename patches/server/{0294-Block-Entity-remove-from-being-called-on-Players.patch => 0288-Block-Entity-remove-from-being-called-on-Players.patch} (100%) rename patches/server/{0295-BlockDestroyEvent.patch => 0289-BlockDestroyEvent.patch} (100%) rename patches/server/{0296-Async-command-map-building.patch => 0290-Async-command-map-building.patch} (100%) rename patches/server/{0297-Implement-Brigadier-Mojang-API.patch => 0291-Implement-Brigadier-Mojang-API.patch} (100%) rename patches/server/{0298-Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch => 0292-Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch} (100%) rename patches/server/{0299-Limit-Client-Sign-length-more.patch => 0293-Limit-Client-Sign-length-more.patch} (100%) rename patches/server/{0300-Handle-Oversized-Tile-Entities-in-chunks.patch => 0294-Handle-Oversized-Tile-Entities-in-chunks.patch} (100%) rename patches/server/{0301-Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch => 0295-Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch} (100%) rename patches/server/{0302-Entity-getEntitySpawnReason.patch => 0296-Entity-getEntitySpawnReason.patch} (100%) rename patches/server/{0303-Fire-event-on-GS4-query.patch => 0297-Fire-event-on-GS4-query.patch} (100%) rename patches/server/{0304-Implement-PlayerPostRespawnEvent.patch => 0298-Implement-PlayerPostRespawnEvent.patch} (100%) rename patches/server/{0305-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch => 0299-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch} (100%) rename patches/server/{0306-Server-Tick-Events.patch => 0300-Server-Tick-Events.patch} (100%) rename patches/server/{0307-PlayerDeathEvent-getItemsToKeep.patch => 0301-PlayerDeathEvent-getItemsToKeep.patch} (100%) rename patches/server/{0308-Optimize-Captured-TileEntity-Lookup.patch => 0302-Optimize-Captured-TileEntity-Lookup.patch} (100%) rename patches/server/{0309-Add-Heightmap-API.patch => 0303-Add-Heightmap-API.patch} (100%) rename patches/server/{0310-Mob-Spawner-API-Enhancements.patch => 0304-Mob-Spawner-API-Enhancements.patch} (100%) rename patches/server/{0311-Fix-CB-call-to-changed-postToMainThread-method.patch => 0305-Fix-CB-call-to-changed-postToMainThread-method.patch} (100%) rename patches/server/{0312-Fix-sounds-when-item-frames-are-modified-MC-123450.patch => 0306-Fix-sounds-when-item-frames-are-modified-MC-123450.patch} (100%) rename patches/server/{0313-Implement-CraftBlockSoundGroup.patch => 0307-Implement-CraftBlockSoundGroup.patch} (100%) rename patches/server/{0314-Configurable-Keep-Spawn-Loaded-range-per-world.patch => 0308-Configurable-Keep-Spawn-Loaded-range-per-world.patch} (100%) rename patches/server/{0315-Allow-Saving-of-Oversized-Chunks.patch => 0309-Allow-Saving-of-Oversized-Chunks.patch} (100%) rename patches/server/{0316-Expose-the-internal-current-tick.patch => 0310-Expose-the-internal-current-tick.patch} (100%) rename patches/server/{0317-Fix-World-isChunkGenerated-calls.patch => 0311-Fix-World-isChunkGenerated-calls.patch} (100%) rename patches/server/{0318-Show-blockstate-location-if-we-failed-to-read-it.patch => 0312-Show-blockstate-location-if-we-failed-to-read-it.patch} (100%) rename patches/server/{0319-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch => 0313-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch} (100%) rename patches/server/{0320-Configurable-projectile-relative-velocity.patch => 0314-Configurable-projectile-relative-velocity.patch} (100%) rename patches/server/{0321-offset-item-frame-ticking.patch => 0315-offset-item-frame-ticking.patch} (100%) rename patches/server/{0322-Fix-MC-158900.patch => 0316-Fix-MC-158900.patch} (100%) rename patches/server/{0323-Prevent-consuming-the-wrong-itemstack.patch => 0317-Prevent-consuming-the-wrong-itemstack.patch} (100%) rename patches/server/{0324-Dont-send-unnecessary-sign-update.patch => 0318-Dont-send-unnecessary-sign-update.patch} (100%) rename patches/server/{0325-Add-option-to-disable-pillager-patrols.patch => 0319-Add-option-to-disable-pillager-patrols.patch} (100%) rename patches/server/{0326-Flat-bedrock-generator-settings.patch => 0320-Flat-bedrock-generator-settings.patch} (100%) rename patches/server/{0327-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch => 0321-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch} (100%) rename patches/server/{0328-MC-145656-Fix-Follow-Range-Initial-Target.patch => 0322-MC-145656-Fix-Follow-Range-Initial-Target.patch} (100%) rename patches/server/{0329-Duplicate-UUID-Resolve-Option.patch => 0323-Duplicate-UUID-Resolve-Option.patch} (100%) rename patches/server/{0330-PlayerDeathEvent-shouldDropExperience.patch => 0324-PlayerDeathEvent-shouldDropExperience.patch} (100%) rename patches/server/{0331-Prevent-bees-loading-chunks-checking-hive-position.patch => 0325-Prevent-bees-loading-chunks-checking-hive-position.patch} (100%) rename patches/server/{0332-Don-t-load-Chunks-from-Hoppers-and-other-things.patch => 0326-Don-t-load-Chunks-from-Hoppers-and-other-things.patch} (100%) rename patches/server/{0333-Optimise-EntityGetter-getPlayerByUUID.patch => 0327-Optimise-EntityGetter-getPlayerByUUID.patch} (100%) rename patches/server/{0334-Fix-items-not-falling-correctly.patch => 0328-Fix-items-not-falling-correctly.patch} (100%) rename patches/server/{0335-Optimize-call-to-getFluid-for-explosions.patch => 0329-Optimize-call-to-getFluid-for-explosions.patch} (100%) rename patches/server/{0336-Fix-last-firework-in-stack-not-having-effects-when-d.patch => 0330-Fix-last-firework-in-stack-not-having-effects-when-d.patch} (100%) rename patches/server/{0337-Entity-Activation-Range-2.0.patch => 0331-Entity-Activation-Range-2.0.patch} (100%) rename patches/server/{0338-Implement-alternative-item-despawn-rate.patch => 0332-Implement-alternative-item-despawn-rate.patch} (100%) rename patches/server/{0339-Tracking-Range-Improvements.patch => 0333-Tracking-Range-Improvements.patch} (100%) rename patches/server/{0340-Fix-items-vanishing-through-end-portal.patch => 0334-Fix-items-vanishing-through-end-portal.patch} (100%) rename patches/server/{0341-implement-optional-per-player-mob-spawns.patch => 0335-implement-optional-per-player-mob-spawns.patch} (100%) rename patches/server/{0342-Bees-get-gravity-in-void.-Fixes-MC-167279.patch => 0336-Bees-get-gravity-in-void.-Fixes-MC-167279.patch} (100%) rename patches/server/{0343-Improve-Block-breakNaturally-API.patch => 0337-Improve-Block-breakNaturally-API.patch} (100%) rename patches/server/{0344-Optimise-getChunkAt-calls-for-loaded-chunks.patch => 0338-Optimise-getChunkAt-calls-for-loaded-chunks.patch} (100%) rename patches/server/{0345-Add-debug-for-sync-chunk-loads.patch => 0339-Add-debug-for-sync-chunk-loads.patch} (100%) rename patches/server/{0346-Remove-garbage-Java-version-check.patch => 0340-Remove-garbage-Java-version-check.patch} (100%) rename patches/server/{0347-Add-ThrownEggHatchEvent.patch => 0341-Add-ThrownEggHatchEvent.patch} (100%) rename patches/server/{0348-Entity-Jump-API.patch => 0342-Entity-Jump-API.patch} (100%) rename patches/server/{0349-Add-option-to-nerf-pigmen-from-nether-portals.patch => 0343-Add-option-to-nerf-pigmen-from-nether-portals.patch} (100%) rename patches/server/{0350-Make-the-GUI-graph-fancier.patch => 0344-Make-the-GUI-graph-fancier.patch} (100%) rename patches/server/{0351-add-hand-to-BlockMultiPlaceEvent.patch => 0345-add-hand-to-BlockMultiPlaceEvent.patch} (100%) rename patches/server/{0352-Validate-tripwire-hook-placement-before-update.patch => 0346-Validate-tripwire-hook-placement-before-update.patch} (100%) rename patches/server/{0353-Add-option-to-allow-iron-golems-to-spawn-in-air.patch => 0347-Add-option-to-allow-iron-golems-to-spawn-in-air.patch} (100%) rename patches/server/{0354-Configurable-chance-of-villager-zombie-infection.patch => 0348-Configurable-chance-of-villager-zombie-infection.patch} (100%) rename patches/server/{0355-Optimise-Chunk-getFluid.patch => 0349-Optimise-Chunk-getFluid.patch} (100%) rename patches/server/{0356-Set-spigots-verbose-world-setting-to-false-by-def.patch => 0350-Set-spigots-verbose-world-setting-to-false-by-def.patch} (100%) rename patches/server/{0357-Add-tick-times-API-and-mspt-command.patch => 0351-Add-tick-times-API-and-mspt-command.patch} (100%) rename patches/server/{0358-Expose-MinecraftServer-isRunning.patch => 0352-Expose-MinecraftServer-isRunning.patch} (100%) rename patches/server/{0359-Add-Raw-Byte-ItemStack-Serialization.patch => 0353-Add-Raw-Byte-ItemStack-Serialization.patch} (100%) rename patches/server/{0360-Pillager-patrol-spawn-settings-and-per-player-option.patch => 0354-Pillager-patrol-spawn-settings-and-per-player-option.patch} (100%) rename patches/server/{0361-Remote-Connections-shouldn-t-hold-up-shutdown.patch => 0355-Remote-Connections-shouldn-t-hold-up-shutdown.patch} (100%) rename patches/server/{0362-Do-not-allow-bees-to-load-chunks-for-beehives.patch => 0356-Do-not-allow-bees-to-load-chunks-for-beehives.patch} (100%) rename patches/server/{0363-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch => 0357-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch} (100%) rename patches/server/{0364-Don-t-tick-dead-players.patch => 0358-Don-t-tick-dead-players.patch} (100%) rename patches/server/{0365-Dead-Player-s-shouldn-t-be-able-to-move.patch => 0359-Dead-Player-s-shouldn-t-be-able-to-move.patch} (100%) rename patches/server/{0366-Optimize-Collision-to-not-load-chunks.patch => 0360-Optimize-Collision-to-not-load-chunks.patch} (100%) rename patches/server/{0367-Don-t-move-existing-players-to-world-spawn.patch => 0361-Don-t-move-existing-players-to-world-spawn.patch} (100%) rename patches/server/{0368-Optimize-GoalSelector-Goal.Flag-Set-operations.patch => 0362-Optimize-GoalSelector-Goal.Flag-Set-operations.patch} (100%) rename patches/server/{0369-Improved-Watchdog-Support.patch => 0363-Improved-Watchdog-Support.patch} (100%) rename patches/server/{0370-Optimize-Pathfinding.patch => 0364-Optimize-Pathfinding.patch} (100%) rename patches/server/{0371-Reduce-Either-Optional-allocation.patch => 0365-Reduce-Either-Optional-allocation.patch} (100%) rename patches/server/{0372-Reduce-memory-footprint-of-NBTTagCompound.patch => 0366-Reduce-memory-footprint-of-NBTTagCompound.patch} (100%) rename patches/server/{0373-Prevent-opening-inventories-when-frozen.patch => 0367-Prevent-opening-inventories-when-frozen.patch} (100%) rename patches/server/{0374-Don-t-run-entity-collision-code-if-not-needed.patch => 0368-Don-t-run-entity-collision-code-if-not-needed.patch} (100%) rename patches/server/{0375-Implement-Player-Client-Options-API.patch => 0369-Implement-Player-Client-Options-API.patch} (100%) rename patches/server/{0376-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch => 0370-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch} (100%) rename patches/server/{0377-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch => 0371-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch} (100%) rename patches/server/{0378-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch => 0372-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch} (100%) rename patches/server/{0379-Add-PlayerAttackEntityCooldownResetEvent.patch => 0373-Add-PlayerAttackEntityCooldownResetEvent.patch} (100%) rename patches/server/{0380-Don-t-fire-BlockFade-on-worldgen-threads.patch => 0374-Don-t-fire-BlockFade-on-worldgen-threads.patch} (100%) rename patches/server/{0381-Add-phantom-creative-and-insomniac-controls.patch => 0375-Add-phantom-creative-and-insomniac-controls.patch} (100%) rename patches/server/{0382-Fix-numerous-item-duplication-issues-and-teleport-is.patch => 0376-Fix-numerous-item-duplication-issues-and-teleport-is.patch} (100%) rename patches/server/{0383-Villager-Restocks-API.patch => 0377-Villager-Restocks-API.patch} (100%) rename patches/server/{0384-Validate-PickItem-Packet-and-kick-for-invalid.patch => 0378-Validate-PickItem-Packet-and-kick-for-invalid.patch} (100%) rename patches/server/{0385-Expose-game-version.patch => 0379-Expose-game-version.patch} (100%) rename patches/server/{0386-Optimize-Voxel-Shape-Merging.patch => 0380-Optimize-Voxel-Shape-Merging.patch} (100%) rename patches/server/{0387-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch => 0381-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch} (100%) rename patches/server/{0388-misc-debugging-dumps.patch => 0382-misc-debugging-dumps.patch} (100%) rename patches/server/{0389-Prevent-teleporting-dead-entities.patch => 0383-Prevent-teleporting-dead-entities.patch} (100%) rename patches/server/{0390-Deobfuscate-stacktraces-in-log-messages-crash-report.patch => 0384-Deobfuscate-stacktraces-in-log-messages-crash-report.patch} (100%) rename patches/server/{0391-Implement-Mob-Goal-API.patch => 0385-Implement-Mob-Goal-API.patch} (100%) rename patches/server/{0392-Add-villager-reputation-API.patch => 0386-Add-villager-reputation-API.patch} (100%) rename patches/server/{0393-Option-for-maximum-exp-value-when-merging-orbs.patch => 0387-Option-for-maximum-exp-value-when-merging-orbs.patch} (100%) rename patches/server/{0394-ExperienceOrbMergeEvent.patch => 0388-ExperienceOrbMergeEvent.patch} (100%) rename patches/server/{0395-Fix-PotionEffect-ignores-icon-flag.patch => 0389-Fix-PotionEffect-ignores-icon-flag.patch} (100%) rename patches/server/{0396-Optimize-brigadier-child-sorting-performance.patch => 0390-Optimize-brigadier-child-sorting-performance.patch} (100%) rename patches/server/{0397-Potential-bed-API.patch => 0391-Potential-bed-API.patch} (100%) rename patches/server/{0398-Wait-for-Async-Tasks-during-shutdown.patch => 0392-Wait-for-Async-Tasks-during-shutdown.patch} (100%) rename patches/server/{0399-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch => 0393-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch} (100%) rename patches/server/{0400-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch => 0394-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch} (100%) rename patches/server/{0401-Reduce-allocation-of-Vec3D-by-entity-tracker.patch => 0395-Reduce-allocation-of-Vec3D-by-entity-tracker.patch} (100%) rename patches/server/{0402-Ensure-safe-gateway-teleport.patch => 0396-Ensure-safe-gateway-teleport.patch} (100%) rename patches/server/{0403-Add-option-for-console-having-all-permissions.patch => 0397-Add-option-for-console-having-all-permissions.patch} (100%) rename patches/server/{0404-Fix-villager-trading-demand-MC-163962.patch => 0398-Fix-villager-trading-demand-MC-163962.patch} (100%) rename patches/server/{0405-Maps-shouldn-t-load-chunks.patch => 0399-Maps-shouldn-t-load-chunks.patch} (100%) rename patches/server/{0406-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch => 0400-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch} (100%) rename patches/server/{0407-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch => 0401-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch} (100%) rename patches/server/{0408-Fix-piston-physics-inconsistency-MC-188840.patch => 0402-Fix-piston-physics-inconsistency-MC-188840.patch} (100%) rename patches/server/{0409-Fix-sand-duping.patch => 0403-Fix-sand-duping.patch} (100%) rename patches/server/{0410-Fix-missing-chunks-due-to-integer-overflow.patch => 0404-Fix-missing-chunks-due-to-integer-overflow.patch} (100%) rename patches/server/{0411-Prevent-position-desync-in-playerconnection-causing-.patch => 0405-Prevent-position-desync-in-playerconnection-causing-.patch} (100%) rename patches/server/{0412-Inventory-getHolder-method-without-block-snapshot.patch => 0406-Inventory-getHolder-method-without-block-snapshot.patch} (100%) rename patches/server/{0413-Improve-Arrow-API.patch => 0407-Improve-Arrow-API.patch} (100%) rename patches/server/{0414-Add-and-implement-PlayerRecipeBookClickEvent.patch => 0408-Add-and-implement-PlayerRecipeBookClickEvent.patch} (100%) rename patches/server/{0415-Hide-sync-chunk-writes-behind-flag.patch => 0409-Hide-sync-chunk-writes-behind-flag.patch} (100%) rename patches/server/{0416-Add-permission-for-command-blocks.patch => 0410-Add-permission-for-command-blocks.patch} (100%) rename patches/server/{0417-Ensure-Entity-AABB-s-are-never-invalid.patch => 0411-Ensure-Entity-AABB-s-are-never-invalid.patch} (100%) rename patches/server/{0418-Fix-Per-World-Difficulty-Remembering-Difficulty.patch => 0412-Fix-Per-World-Difficulty-Remembering-Difficulty.patch} (100%) rename patches/server/{0419-Paper-dumpitem-command.patch => 0413-Paper-dumpitem-command.patch} (100%) rename patches/server/{0420-Improve-Legacy-Component-serialization-size.patch => 0414-Improve-Legacy-Component-serialization-size.patch} (100%) rename patches/server/{0421-Optimize-Bit-Operations-by-inlining.patch => 0415-Optimize-Bit-Operations-by-inlining.patch} (100%) rename patches/server/{0422-Add-Plugin-Tickets-to-API-Chunk-Methods.patch => 0416-Add-Plugin-Tickets-to-API-Chunk-Methods.patch} (100%) rename patches/server/{0423-incremental-chunk-and-player-saving.patch => 0417-incremental-chunk-and-player-saving.patch} (100%) rename patches/server/{0424-Support-old-UUID-format-for-NBT.patch => 0418-Support-old-UUID-format-for-NBT.patch} (100%) rename patches/server/{0425-Clean-up-duplicated-GameProfile-Properties.patch => 0419-Clean-up-duplicated-GameProfile-Properties.patch} (100%) rename patches/server/{0426-Convert-legacy-attributes-in-Item-Meta.patch => 0420-Convert-legacy-attributes-in-Item-Meta.patch} (100%) rename patches/server/{0427-Remove-some-streams-from-structures.patch => 0421-Remove-some-streams-from-structures.patch} (100%) rename patches/server/{0428-Remove-streams-from-classes-related-villager-gossip.patch => 0422-Remove-streams-from-classes-related-villager-gossip.patch} (100%) rename patches/server/{0429-Support-components-in-ItemMeta.patch => 0423-Support-components-in-ItemMeta.patch} (100%) rename patches/server/{0430-Improve-fix-EntityTargetLivingEntityEvent.patch => 0424-Improve-fix-EntityTargetLivingEntityEvent.patch} (100%) rename patches/server/{0431-Add-entity-liquid-API.patch => 0425-Add-entity-liquid-API.patch} (100%) rename patches/server/{0432-Update-itemstack-legacy-name-and-lore.patch => 0426-Update-itemstack-legacy-name-and-lore.patch} (100%) rename patches/server/{0433-Spawn-player-in-correct-world-on-login.patch => 0427-Spawn-player-in-correct-world-on-login.patch} (100%) rename patches/server/{0434-Add-PrepareResultEvent.patch => 0428-Add-PrepareResultEvent.patch} (100%) rename patches/server/{0435-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch => 0429-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch} (100%) rename patches/server/{0436-Optimize-NetworkManager-Exception-Handling.patch => 0430-Optimize-NetworkManager-Exception-Handling.patch} (100%) rename patches/server/{0437-Fix-arrows-never-despawning-MC-125757.patch => 0431-Fix-arrows-never-despawning-MC-125757.patch} (100%) rename patches/server/{0438-Thread-Safe-Vanilla-Command-permission-checking.patch => 0432-Thread-Safe-Vanilla-Command-permission-checking.patch} (100%) rename patches/server/{0439-Fix-SPIGOT-5989.patch => 0433-Fix-SPIGOT-5989.patch} (100%) rename patches/server/{0440-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch => 0434-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch} (100%) rename patches/server/{0441-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch => 0435-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch} (100%) rename patches/server/{0442-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch => 0436-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch} (100%) rename patches/server/{0443-Fix-some-rails-connecting-improperly.patch => 0437-Fix-some-rails-connecting-improperly.patch} (100%) rename patches/server/{0444-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch => 0438-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch} (100%) rename patches/server/{0445-Do-not-let-the-server-load-chunks-from-newer-version.patch => 0439-Do-not-let-the-server-load-chunks-from-newer-version.patch} (100%) rename patches/server/{0446-Brand-support.patch => 0440-Brand-support.patch} (100%) rename patches/server/{0447-Add-setMaxPlayers-API.patch => 0441-Add-setMaxPlayers-API.patch} (100%) rename patches/server/{0448-Add-playPickupItemAnimation-to-LivingEntity.patch => 0442-Add-playPickupItemAnimation-to-LivingEntity.patch} (100%) rename patches/server/{0449-Don-t-require-FACING-data.patch => 0443-Don-t-require-FACING-data.patch} (100%) rename patches/server/{0450-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch => 0444-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch} (100%) rename patches/server/{0451-Add-moon-phase-API.patch => 0445-Add-moon-phase-API.patch} (100%) rename patches/server/{0452-Prevent-headless-pistons-from-being-created.patch => 0446-Prevent-headless-pistons-from-being-created.patch} (100%) rename patches/server/{0453-Add-BellRingEvent.patch => 0447-Add-BellRingEvent.patch} (100%) rename patches/server/{0454-Add-zombie-targets-turtle-egg-config.patch => 0448-Add-zombie-targets-turtle-egg-config.patch} (100%) rename patches/server/{0455-Buffer-joins-to-world.patch => 0449-Buffer-joins-to-world.patch} (100%) rename patches/server/{0456-Eigencraft-redstone-implementation.patch => 0450-Eigencraft-redstone-implementation.patch} (100%) rename patches/server/{0457-Fix-hex-colors-not-working-in-some-kick-messages.patch => 0451-Fix-hex-colors-not-working-in-some-kick-messages.patch} (100%) rename patches/server/{0458-PortalCreateEvent-needs-to-know-its-entity.patch => 0452-PortalCreateEvent-needs-to-know-its-entity.patch} (100%) rename patches/server/{0459-Fix-CraftTeam-null-check.patch => 0453-Fix-CraftTeam-null-check.patch} (100%) rename patches/server/{0460-Add-more-Evoker-API.patch => 0454-Add-more-Evoker-API.patch} (100%) rename patches/server/{0461-Add-methods-to-get-translation-keys.patch => 0455-Add-methods-to-get-translation-keys.patch} (100%) rename patches/server/{0462-Create-HoverEvent-from-ItemStack-Entity.patch => 0456-Create-HoverEvent-from-ItemStack-Entity.patch} (100%) rename patches/server/{0463-Cache-block-data-strings.patch => 0457-Cache-block-data-strings.patch} (100%) rename patches/server/{0464-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch => 0458-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch} (100%) rename patches/server/{0465-Add-additional-open-container-api-to-HumanEntity.patch => 0459-Add-additional-open-container-api-to-HumanEntity.patch} (100%) rename patches/server/{0466-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch => 0460-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch} (100%) rename patches/server/{0467-Extend-block-drop-capture-to-capture-all-items-added.patch => 0461-Extend-block-drop-capture-to-capture-all-items-added.patch} (100%) rename patches/server/{0468-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch => 0462-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch} (100%) rename patches/server/{0469-Lazily-track-plugin-scoreboards-by-default.patch => 0463-Lazily-track-plugin-scoreboards-by-default.patch} (100%) rename patches/server/{0470-Entity-isTicking.patch => 0464-Entity-isTicking.patch} (100%) rename patches/server/{0471-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch => 0465-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch} (100%) rename patches/server/{0472-Fix-Concurrency-issue-in-ShufflingList.patch => 0466-Fix-Concurrency-issue-in-ShufflingList.patch} (100%) rename patches/server/{0473-Reset-Ender-Crystals-on-Dragon-Spawn.patch => 0467-Reset-Ender-Crystals-on-Dragon-Spawn.patch} (100%) rename patches/server/{0474-Fix-for-large-move-vectors-crashing-server.patch => 0468-Fix-for-large-move-vectors-crashing-server.patch} (100%) rename patches/server/{0475-Optimise-getType-calls.patch => 0469-Optimise-getType-calls.patch} (100%) rename patches/server/{0476-Villager-resetOffers.patch => 0470-Villager-resetOffers.patch} (100%) rename patches/server/{0477-Retain-block-place-order-when-capturing-blockstates.patch => 0471-Retain-block-place-order-when-capturing-blockstates.patch} (100%) rename patches/server/{0478-Reduce-blockpos-allocation-from-pathfinding.patch => 0472-Reduce-blockpos-allocation-from-pathfinding.patch} (100%) rename patches/server/{0479-Fix-item-locations-dropped-from-campfires.patch => 0473-Fix-item-locations-dropped-from-campfires.patch} (100%) rename patches/server/{0480-Player-elytra-boost-API.patch => 0474-Player-elytra-boost-API.patch} (100%) rename patches/server/{0481-Fixed-TileEntityBell-memory-leak.patch => 0475-Fixed-TileEntityBell-memory-leak.patch} (100%) rename patches/server/{0482-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch => 0476-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch} (100%) rename patches/server/{0483-Add-getOfflinePlayerIfCached-String.patch => 0477-Add-getOfflinePlayerIfCached-String.patch} (100%) rename patches/server/{0484-Add-ignore-discounts-API.patch => 0478-Add-ignore-discounts-API.patch} (100%) rename patches/server/{0485-Toggle-for-removing-existing-dragon.patch => 0479-Toggle-for-removing-existing-dragon.patch} (100%) rename patches/server/{0486-Fix-client-lag-on-advancement-loading.patch => 0480-Fix-client-lag-on-advancement-loading.patch} (100%) rename patches/server/{0487-Item-no-age-no-player-pickup.patch => 0481-Item-no-age-no-player-pickup.patch} (100%) rename patches/server/{0488-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch => 0482-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch} (100%) rename patches/server/{0489-Beacon-API-custom-effect-ranges.patch => 0483-Beacon-API-custom-effect-ranges.patch} (100%) rename patches/server/{0490-Add-API-for-quit-reason.patch => 0484-Add-API-for-quit-reason.patch} (100%) rename patches/server/{0491-Add-Wandering-Trader-spawn-rate-config-options.patch => 0485-Add-Wandering-Trader-spawn-rate-config-options.patch} (100%) rename patches/server/{0492-Expose-world-spawn-angle.patch => 0486-Expose-world-spawn-angle.patch} (100%) rename patches/server/{0493-Add-Destroy-Speed-API.patch => 0487-Add-Destroy-Speed-API.patch} (100%) rename patches/server/{0494-Fix-Player-spawnParticle-x-y-z-precision-loss.patch => 0488-Fix-Player-spawnParticle-x-y-z-precision-loss.patch} (100%) rename patches/server/{0495-Add-LivingEntity-clearActiveItem.patch => 0489-Add-LivingEntity-clearActiveItem.patch} (100%) rename patches/server/{0496-Add-PlayerItemCooldownEvent.patch => 0490-Add-PlayerItemCooldownEvent.patch} (100%) rename patches/server/{0497-Significantly-improve-performance-of-the-end-generat.patch => 0491-Significantly-improve-performance-of-the-end-generat.patch} (100%) rename patches/server/{0498-More-lightning-API.patch => 0492-More-lightning-API.patch} (100%) rename patches/server/{0499-Climbing-should-not-bypass-cramming-gamerule.patch => 0493-Climbing-should-not-bypass-cramming-gamerule.patch} (100%) rename patches/server/{0500-Added-missing-default-perms-for-commands.patch => 0494-Added-missing-default-perms-for-commands.patch} (100%) rename patches/server/{0501-Add-PlayerShearBlockEvent.patch => 0495-Add-PlayerShearBlockEvent.patch} (100%) rename patches/server/{0502-Fix-curing-zombie-villager-discount-exploit.patch => 0496-Fix-curing-zombie-villager-discount-exploit.patch} (100%) rename patches/server/{0503-Limit-recipe-packets.patch => 0497-Limit-recipe-packets.patch} (100%) rename patches/server/{0504-Fix-CraftSound-backwards-compatibility.patch => 0498-Fix-CraftSound-backwards-compatibility.patch} (100%) rename patches/server/{0505-Player-Chunk-Load-Unload-Events.patch => 0499-Player-Chunk-Load-Unload-Events.patch} (100%) rename patches/server/{0506-Optimize-Dynamic-get-Missing-Keys.patch => 0500-Optimize-Dynamic-get-Missing-Keys.patch} (100%) rename patches/server/{0507-Expose-LivingEntity-hurt-direction.patch => 0501-Expose-LivingEntity-hurt-direction.patch} (100%) rename patches/server/{0508-Add-OBSTRUCTED-reason-to-BedEnterResult.patch => 0502-Add-OBSTRUCTED-reason-to-BedEnterResult.patch} (100%) rename patches/server/{0509-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch => 0503-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch} (100%) rename patches/server/{0510-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch => 0504-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch} (100%) rename patches/server/{0511-Implement-TargetHitEvent.patch => 0505-Implement-TargetHitEvent.patch} (100%) rename patches/server/{0512-MC-4-Fix-item-position-desync.patch => 0506-MC-4-Fix-item-position-desync.patch} (100%) rename patches/server/{0513-Additional-Block-Material-API-s.patch => 0507-Additional-Block-Material-API-s.patch} (100%) rename patches/server/{0514-Fix-harming-potion-dupe.patch => 0508-Fix-harming-potion-dupe.patch} (100%) rename patches/server/{0515-Implement-API-to-get-Material-from-Boats-and-Minecar.patch => 0509-Implement-API-to-get-Material-from-Boats-and-Minecar.patch} (100%) rename patches/server/{0516-Cache-burn-durations.patch => 0510-Cache-burn-durations.patch} (100%) rename patches/server/{0517-Allow-disabling-mob-spawner-spawn-egg-transformation.patch => 0511-Allow-disabling-mob-spawner-spawn-egg-transformation.patch} (100%) rename patches/server/{0518-Fix-Not-a-string-Map-Conversion-spam.patch => 0512-Fix-Not-a-string-Map-Conversion-spam.patch} (100%) rename patches/server/{0519-Implement-PlayerFlowerPotManipulateEvent.patch => 0513-Implement-PlayerFlowerPotManipulateEvent.patch} (100%) rename patches/server/{0520-Fix-interact-event-not-being-called-in-adventure.patch => 0514-Fix-interact-event-not-being-called-in-adventure.patch} (100%) rename patches/server/{0521-Zombie-API-breaking-doors.patch => 0515-Zombie-API-breaking-doors.patch} (100%) rename patches/server/{0522-Fix-nerfed-slime-when-splitting.patch => 0516-Fix-nerfed-slime-when-splitting.patch} (100%) rename patches/server/{0523-Add-EntityLoadCrossbowEvent.patch => 0517-Add-EntityLoadCrossbowEvent.patch} (100%) rename patches/server/{0524-Added-WorldGameRuleChangeEvent.patch => 0518-Added-WorldGameRuleChangeEvent.patch} (100%) rename patches/server/{0525-Added-ServerResourcesReloadedEvent.patch => 0519-Added-ServerResourcesReloadedEvent.patch} (100%) rename patches/server/{0526-Added-world-settings-for-mobs-picking-up-loot.patch => 0520-Added-world-settings-for-mobs-picking-up-loot.patch} (100%) rename patches/server/{0527-Implemented-BlockFailedDispenseEvent.patch => 0521-Implemented-BlockFailedDispenseEvent.patch} (100%) rename patches/server/{0528-Added-PlayerLecternPageChangeEvent.patch => 0522-Added-PlayerLecternPageChangeEvent.patch} (100%) rename patches/server/{0529-Added-PlayerLoomPatternSelectEvent.patch => 0523-Added-PlayerLoomPatternSelectEvent.patch} (100%) rename patches/server/{0530-Configurable-door-breaking-difficulty.patch => 0524-Configurable-door-breaking-difficulty.patch} (100%) rename patches/server/{0531-Empty-commands-shall-not-be-dispatched.patch => 0525-Empty-commands-shall-not-be-dispatched.patch} (100%) rename patches/server/{0532-Implement-API-to-expose-exact-interaction-point.patch => 0526-Implement-API-to-expose-exact-interaction-point.patch} (100%) rename patches/server/{0533-Remove-stale-POIs.patch => 0527-Remove-stale-POIs.patch} (100%) rename patches/server/{0534-Fix-villager-boat-exploit.patch => 0528-Fix-villager-boat-exploit.patch} (100%) rename patches/server/{0535-Add-sendOpLevel-API.patch => 0529-Add-sendOpLevel-API.patch} (100%) rename patches/server/{0536-TODO-Registry-Modification-API.patch => 0530-TODO-Registry-Modification-API.patch} (100%) rename patches/server/{0537-Add-StructuresLocateEvent.patch => 0531-Add-StructuresLocateEvent.patch} (100%) rename patches/server/{0538-Collision-option-for-requiring-a-player-participant.patch => 0532-Collision-option-for-requiring-a-player-participant.patch} (100%) rename patches/server/{0539-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch => 0533-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch} (100%) rename patches/server/{0540-Return-chat-component-with-empty-text-instead-of-thr.patch => 0534-Return-chat-component-with-empty-text-instead-of-thr.patch} (100%) rename patches/server/{0541-Make-schedule-command-per-world.patch => 0535-Make-schedule-command-per-world.patch} (100%) rename patches/server/{0542-Configurable-max-leash-distance.patch => 0536-Configurable-max-leash-distance.patch} (100%) rename patches/server/{0543-Implement-BlockPreDispenseEvent.patch => 0537-Implement-BlockPreDispenseEvent.patch} (100%) rename patches/server/{0544-Added-firing-of-PlayerChangeBeaconEffectEvent.patch => 0538-Added-firing-of-PlayerChangeBeaconEffectEvent.patch} (100%) rename patches/server/{0545-Add-toggle-for-always-placing-the-dragon-egg.patch => 0539-Add-toggle-for-always-placing-the-dragon-egg.patch} (100%) rename patches/server/{0546-Added-PlayerStonecutterRecipeSelectEvent.patch => 0540-Added-PlayerStonecutterRecipeSelectEvent.patch} (100%) rename patches/server/{0547-Add-dropLeash-variable-to-EntityUnleashEvent.patch => 0541-Add-dropLeash-variable-to-EntityUnleashEvent.patch} (100%) rename patches/server/{0548-Reset-shield-blocking-on-dimension-change.patch => 0542-Reset-shield-blocking-on-dimension-change.patch} (100%) rename patches/server/{0549-add-DragonEggFormEvent.patch => 0543-add-DragonEggFormEvent.patch} (100%) rename patches/server/{0550-EntityMoveEvent.patch => 0544-EntityMoveEvent.patch} (100%) rename patches/server/{0551-added-option-to-disable-pathfinding-updates-on-block.patch => 0545-added-option-to-disable-pathfinding-updates-on-block.patch} (100%) rename patches/server/{0552-Inline-shift-direction-fields.patch => 0546-Inline-shift-direction-fields.patch} (100%) rename patches/server/{0553-Allow-adding-items-to-BlockDropItemEvent.patch => 0547-Allow-adding-items-to-BlockDropItemEvent.patch} (100%) rename patches/server/{0554-Add-getMainThreadExecutor-to-BukkitScheduler.patch => 0548-Add-getMainThreadExecutor-to-BukkitScheduler.patch} (100%) rename patches/server/{0555-living-entity-allow-attribute-registration.patch => 0549-living-entity-allow-attribute-registration.patch} (100%) rename patches/server/{0556-fix-dead-slime-setSize-invincibility.patch => 0550-fix-dead-slime-setSize-invincibility.patch} (100%) rename patches/server/{0557-Merchant-getRecipes-should-return-an-immutable-list.patch => 0551-Merchant-getRecipes-should-return-an-immutable-list.patch} (100%) rename patches/server/{0558-Add-support-for-hex-color-codes-in-console.patch => 0552-Add-support-for-hex-color-codes-in-console.patch} (100%) rename patches/server/{0559-Expose-Tracked-Players.patch => 0553-Expose-Tracked-Players.patch} (100%) rename patches/server/{0560-Remove-streams-from-SensorNearest.patch => 0554-Remove-streams-from-SensorNearest.patch} (100%) rename patches/server/{0561-Throw-proper-exception-on-empty-JsonList-file.patch => 0555-Throw-proper-exception-on-empty-JsonList-file.patch} (100%) rename patches/server/{0562-Improve-ServerGUI.patch => 0556-Improve-ServerGUI.patch} (100%) rename patches/server/{0563-fix-converting-txt-to-json-file.patch => 0557-fix-converting-txt-to-json-file.patch} (100%) rename patches/server/{0564-Add-worldborder-events.patch => 0558-Add-worldborder-events.patch} (100%) rename patches/server/{0565-added-PlayerNameEntityEvent.patch => 0559-added-PlayerNameEntityEvent.patch} (100%) rename patches/server/{0566-Prevent-grindstones-from-overstacking-items.patch => 0560-Prevent-grindstones-from-overstacking-items.patch} (100%) rename patches/server/{0567-Add-recipe-to-cook-events.patch => 0561-Add-recipe-to-cook-events.patch} (100%) rename patches/server/{0568-Add-Block-isValidTool.patch => 0562-Add-Block-isValidTool.patch} (100%) rename patches/server/{0569-Allow-using-signs-inside-spawn-protection.patch => 0563-Allow-using-signs-inside-spawn-protection.patch} (100%) rename patches/server/{0570-Expand-world-key-API.patch => 0564-Expand-world-key-API.patch} (100%) rename patches/server/{0571-Add-fast-alternative-constructor-for-Rotations.patch => 0565-Add-fast-alternative-constructor-for-Rotations.patch} (100%) rename patches/server/{0572-Item-Rarity-API.patch => 0566-Item-Rarity-API.patch} (100%) rename patches/server/{0573-copy-TESign-isEditable-from-snapshots.patch => 0567-copy-TESign-isEditable-from-snapshots.patch} (100%) rename patches/server/{0574-Drop-carried-item-when-player-has-disconnected.patch => 0568-Drop-carried-item-when-player-has-disconnected.patch} (100%) rename patches/server/{0575-forced-whitelist-use-configurable-kick-message.patch => 0569-forced-whitelist-use-configurable-kick-message.patch} (100%) rename patches/server/{0576-Don-t-ignore-result-of-PlayerEditBookEvent.patch => 0570-Don-t-ignore-result-of-PlayerEditBookEvent.patch} (100%) rename patches/server/{0577-Expose-protocol-version.patch => 0571-Expose-protocol-version.patch} (100%) rename patches/server/{0578-Enhance-console-tab-completions-for-brigadier-comman.patch => 0572-Enhance-console-tab-completions-for-brigadier-comman.patch} (100%) rename patches/server/{0579-Fix-PlayerItemConsumeEvent-cancelling-properly.patch => 0573-Fix-PlayerItemConsumeEvent-cancelling-properly.patch} (100%) rename patches/server/{0580-Add-bypass-host-check.patch => 0574-Add-bypass-host-check.patch} (100%) rename patches/server/{0581-Set-area-affect-cloud-rotation.patch => 0575-Set-area-affect-cloud-rotation.patch} (100%) rename patches/server/{0582-add-isDeeplySleeping-to-HumanEntity.patch => 0576-add-isDeeplySleeping-to-HumanEntity.patch} (100%) rename patches/server/{0583-add-consumeFuel-to-FurnaceBurnEvent.patch => 0577-add-consumeFuel-to-FurnaceBurnEvent.patch} (100%) rename patches/server/{0584-add-get-set-drop-chance-to-EntityEquipment.patch => 0578-add-get-set-drop-chance-to-EntityEquipment.patch} (100%) rename patches/server/{0585-fix-PigZombieAngerEvent-cancellation.patch => 0579-fix-PigZombieAngerEvent-cancellation.patch} (100%) rename patches/server/{0586-fix-PlayerItemHeldEvent-firing-twice.patch => 0580-fix-PlayerItemHeldEvent-firing-twice.patch} (100%) rename patches/server/{0587-Added-PlayerDeepSleepEvent.patch => 0581-Added-PlayerDeepSleepEvent.patch} (100%) rename patches/server/{0588-More-World-API.patch => 0582-More-World-API.patch} (100%) rename patches/server/{0589-Added-PlayerBedFailEnterEvent.patch => 0583-Added-PlayerBedFailEnterEvent.patch} (100%) rename patches/server/{0590-Implement-methods-to-convert-between-Component-and-B.patch => 0584-Implement-methods-to-convert-between-Component-and-B.patch} (100%) rename patches/server/{0591-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch => 0585-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch} (100%) rename patches/server/{0592-Introduce-beacon-activation-deactivation-events.patch => 0586-Introduce-beacon-activation-deactivation-events.patch} (100%) rename patches/server/{0593-add-RespawnFlags-to-PlayerRespawnEvent.patch => 0587-add-RespawnFlags-to-PlayerRespawnEvent.patch} (100%) rename patches/server/{0594-Add-Channel-initialization-listeners.patch => 0588-Add-Channel-initialization-listeners.patch} (100%) rename patches/server/{0595-Send-empty-commands-if-tab-completion-is-disabled.patch => 0589-Send-empty-commands-if-tab-completion-is-disabled.patch} (100%) rename patches/server/{0596-Add-more-WanderingTrader-API.patch => 0590-Add-more-WanderingTrader-API.patch} (100%) rename patches/server/{0597-Add-EntityBlockStorage-clearEntities.patch => 0591-Add-EntityBlockStorage-clearEntities.patch} (100%) rename patches/server/{0598-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch => 0592-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch} (100%) rename patches/server/{0599-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch => 0593-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch} (100%) rename patches/server/{0600-Inventory-close.patch => 0594-Inventory-close.patch} (100%) rename patches/server/{0601-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch => 0595-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch} (100%) rename patches/server/{0602-Fix-CraftPotionBrewer-cache.patch => 0596-Fix-CraftPotionBrewer-cache.patch} (100%) rename patches/server/{0603-Add-basic-Datapack-API.patch => 0597-Add-basic-Datapack-API.patch} (100%) rename patches/server/{0604-Add-environment-variable-to-disable-server-gui.patch => 0598-Add-environment-variable-to-disable-server-gui.patch} (100%) rename patches/server/{0605-additions-to-PlayerGameModeChangeEvent.patch => 0599-additions-to-PlayerGameModeChangeEvent.patch} (100%) rename patches/server/{0606-ItemStack-repair-check-API.patch => 0600-ItemStack-repair-check-API.patch} (100%) rename patches/server/{0607-More-Enchantment-API.patch => 0601-More-Enchantment-API.patch} (100%) rename patches/server/{0608-Move-range-check-for-block-placing-up.patch => 0602-Move-range-check-for-block-placing-up.patch} (100%) rename patches/server/{0609-Fix-and-optimise-world-force-upgrading.patch => 0603-Fix-and-optimise-world-force-upgrading.patch} (100%) rename patches/server/{0610-Add-Mob-lookAt-API.patch => 0604-Add-Mob-lookAt-API.patch} (100%) rename patches/server/{0611-Add-Unix-domain-socket-support.patch => 0605-Add-Unix-domain-socket-support.patch} (100%) rename patches/server/{0612-Add-EntityInsideBlockEvent.patch => 0606-Add-EntityInsideBlockEvent.patch} (100%) rename patches/server/{0613-Attributes-API-for-item-defaults.patch => 0607-Attributes-API-for-item-defaults.patch} (100%) rename patches/server/{0614-Add-cause-to-Weather-ThunderChangeEvents.patch => 0608-Add-cause-to-Weather-ThunderChangeEvents.patch} (100%) rename patches/server/{0615-More-Lidded-Block-API.patch => 0609-More-Lidded-Block-API.patch} (100%) rename patches/server/{0616-Limit-item-frame-cursors-on-maps.patch => 0610-Limit-item-frame-cursors-on-maps.patch} (100%) rename patches/server/{0617-Add-PlayerKickEvent-causes.patch => 0611-Add-PlayerKickEvent-causes.patch} (100%) rename patches/server/{0618-Add-PufferFishStateChangeEvent.patch => 0612-Add-PufferFishStateChangeEvent.patch} (100%) rename patches/server/{0619-Fix-PlayerBucketEmptyEvent-result-itemstack.patch => 0613-Fix-PlayerBucketEmptyEvent-result-itemstack.patch} (100%) rename patches/server/{0620-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch => 0614-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch} (100%) rename patches/server/{0621-Add-option-to-fix-items-merging-through-walls.patch => 0615-Add-option-to-fix-items-merging-through-walls.patch} (100%) rename patches/server/{0622-Add-BellRevealRaiderEvent.patch => 0616-Add-BellRevealRaiderEvent.patch} (100%) rename patches/server/{0623-Fix-invulnerable-end-crystals.patch => 0617-Fix-invulnerable-end-crystals.patch} (100%) rename patches/server/{0624-Add-ElderGuardianAppearanceEvent.patch => 0618-Add-ElderGuardianAppearanceEvent.patch} (100%) rename patches/server/{0625-Fix-dangerous-end-portal-logic.patch => 0619-Fix-dangerous-end-portal-logic.patch} (100%) rename patches/server/{0626-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch => 0620-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch} (100%) rename patches/server/{0627-Make-item-validations-configurable.patch => 0621-Make-item-validations-configurable.patch} (100%) rename patches/server/{0628-Line-Of-Sight-Changes.patch => 0622-Line-Of-Sight-Changes.patch} (100%) rename patches/server/{0629-add-per-world-spawn-limits.patch => 0623-add-per-world-spawn-limits.patch} (100%) rename patches/server/{0630-Fix-potions-splash-events.patch => 0624-Fix-potions-splash-events.patch} (100%) rename patches/server/{0631-Add-more-LimitedRegion-API.patch => 0625-Add-more-LimitedRegion-API.patch} (100%) rename patches/server/{0632-Fix-PlayerDropItemEvent-using-wrong-item.patch => 0626-Fix-PlayerDropItemEvent-using-wrong-item.patch} (100%) rename patches/server/{0633-Missing-Entity-Behavior-API.patch => 0627-Missing-Entity-Behavior-API.patch} (100%) rename patches/server/{0634-Ensure-disconnect-for-book-edit-is-called-on-main.patch => 0628-Ensure-disconnect-for-book-edit-is-called-on-main.patch} (100%) rename patches/server/{0635-Fix-return-value-of-Block-applyBoneMeal-always-being.patch => 0629-Fix-return-value-of-Block-applyBoneMeal-always-being.patch} (100%) rename patches/server/{0636-Use-getChunkIfLoadedImmediately-in-places.patch => 0630-Use-getChunkIfLoadedImmediately-in-places.patch} (100%) rename patches/server/{0637-Fix-commands-from-signs-not-firing-command-events.patch => 0631-Fix-commands-from-signs-not-firing-command-events.patch} (100%) rename patches/server/{0638-Adds-PlayerArmSwingEvent.patch => 0632-Adds-PlayerArmSwingEvent.patch} (100%) rename patches/server/{0639-Fixes-kick-event-leave-message-not-being-sent.patch => 0633-Fixes-kick-event-leave-message-not-being-sent.patch} (100%) rename patches/server/{0640-Add-config-for-mobs-immune-to-default-effects.patch => 0634-Add-config-for-mobs-immune-to-default-effects.patch} (100%) rename patches/server/{0641-Fix-incorrect-message-for-outdated-client.patch => 0635-Fix-incorrect-message-for-outdated-client.patch} (100%) rename patches/server/{0642-Don-t-apply-cramming-damage-to-players.patch => 0636-Don-t-apply-cramming-damage-to-players.patch} (100%) rename patches/server/{0643-Rate-options-and-timings-for-sensors-and-behaviors.patch => 0637-Rate-options-and-timings-for-sensors-and-behaviors.patch} (100%) rename patches/server/{0644-Add-a-bunch-of-missing-forceDrop-toggles.patch => 0638-Add-a-bunch-of-missing-forceDrop-toggles.patch} (100%) rename patches/server/{0645-Stinger-API.patch => 0639-Stinger-API.patch} (100%) rename patches/server/{0646-Fix-incosistency-issue-with-empty-map-items-in-CB.patch => 0640-Fix-incosistency-issue-with-empty-map-items-in-CB.patch} (100%) rename patches/server/{0647-Add-System.out-err-catcher.patch => 0641-Add-System.out-err-catcher.patch} (100%) rename patches/server/{0648-Fix-test-not-bootstrapping.patch => 0642-Fix-test-not-bootstrapping.patch} (100%) rename patches/server/{0649-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch => 0643-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch} (100%) rename patches/server/{0650-Improve-boat-collision-performance.patch => 0644-Improve-boat-collision-performance.patch} (100%) rename patches/server/{0651-Prevent-AFK-kick-while-watching-end-credits.patch => 0645-Prevent-AFK-kick-while-watching-end-credits.patch} (100%) rename patches/server/{0652-Add-PlayerSetSpawnEvent.patch => 0646-Add-PlayerSetSpawnEvent.patch} (100%) rename patches/server/{0653-Make-hoppers-respect-inventory-max-stack-size.patch => 0647-Make-hoppers-respect-inventory-max-stack-size.patch} (100%) rename patches/server/{0654-Optimize-entity-tracker-passenger-checks.patch => 0648-Optimize-entity-tracker-passenger-checks.patch} (100%) rename patches/server/{0655-Config-option-for-Piglins-guarding-chests.patch => 0649-Config-option-for-Piglins-guarding-chests.patch} (100%) rename patches/server/{0656-Added-EntityDamageItemEvent.patch => 0650-Added-EntityDamageItemEvent.patch} (100%) rename patches/server/{0657-Optimize-indirect-passenger-iteration.patch => 0651-Optimize-indirect-passenger-iteration.patch} (100%) rename patches/server/{0658-Configurable-item-frame-map-cursor-update-interval.patch => 0652-Configurable-item-frame-map-cursor-update-interval.patch} (100%) rename patches/server/{0659-Make-EntityUnleashEvent-cancellable.patch => 0653-Make-EntityUnleashEvent-cancellable.patch} (100%) rename patches/server/{0660-Clear-bucket-NBT-after-dispense.patch => 0654-Clear-bucket-NBT-after-dispense.patch} (100%) rename patches/server/{0661-Change-EnderEye-target-without-changing-other-things.patch => 0655-Change-EnderEye-target-without-changing-other-things.patch} (100%) rename patches/server/{0662-Add-BlockBreakBlockEvent.patch => 0656-Add-BlockBreakBlockEvent.patch} (100%) rename patches/server/{0663-Option-to-prevent-NBT-copy-in-smithing-recipes.patch => 0657-Option-to-prevent-NBT-copy-in-smithing-recipes.patch} (100%) rename patches/server/{0664-More-CommandBlock-API.patch => 0658-More-CommandBlock-API.patch} (100%) rename patches/server/{0665-Add-missing-team-sidebar-display-slots.patch => 0659-Add-missing-team-sidebar-display-slots.patch} (100%) rename patches/server/{0666-Add-back-EntityPortalExitEvent.patch => 0660-Add-back-EntityPortalExitEvent.patch} (100%) rename patches/server/{0667-Add-methods-to-find-targets-for-lightning-strikes.patch => 0661-Add-methods-to-find-targets-for-lightning-strikes.patch} (100%) rename patches/server/{0668-Get-entity-default-attributes.patch => 0662-Get-entity-default-attributes.patch} (100%) rename patches/server/{0669-Left-handed-API.patch => 0663-Left-handed-API.patch} (100%) rename patches/server/{0670-Add-more-advancement-API.patch => 0664-Add-more-advancement-API.patch} (100%) rename patches/server/{0671-Add-ItemFactory-getSpawnEgg-API.patch => 0665-Add-ItemFactory-getSpawnEgg-API.patch} (100%) rename patches/server/{0672-Add-critical-damage-API.patch => 0666-Add-critical-damage-API.patch} (100%) rename patches/server/{0673-Fix-issues-with-mob-conversion.patch => 0667-Fix-issues-with-mob-conversion.patch} (100%) rename patches/server/{0674-Add-isCollidable-methods-to-various-places.patch => 0668-Add-isCollidable-methods-to-various-places.patch} (100%) rename patches/server/{0675-Goat-ram-API.patch => 0669-Goat-ram-API.patch} (100%) rename patches/server/{0676-Add-API-for-resetting-a-single-score.patch => 0670-Add-API-for-resetting-a-single-score.patch} (100%) rename patches/server/{0677-Add-Raw-Byte-Entity-Serialization.patch => 0671-Add-Raw-Byte-Entity-Serialization.patch} (100%) rename patches/server/{0678-Vanilla-command-permission-fixes.patch => 0672-Vanilla-command-permission-fixes.patch} (100%) rename patches/server/{0679-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch => 0673-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch} (100%) rename patches/server/{0680-Fix-GameProfileCache-concurrency.patch => 0674-Fix-GameProfileCache-concurrency.patch} (100%) rename patches/server/{0681-Improve-and-expand-AsyncCatcher.patch => 0675-Improve-and-expand-AsyncCatcher.patch} (100%) rename patches/server/{0682-Add-paper-mobcaps-and-paper-playermobcaps.patch => 0676-Add-paper-mobcaps-and-paper-playermobcaps.patch} (100%) rename patches/server/{0683-Sanitize-ResourceLocation-error-logging.patch => 0677-Sanitize-ResourceLocation-error-logging.patch} (100%) rename patches/server/{0684-Optimise-general-POI-access.patch => 0678-Optimise-general-POI-access.patch} (100%) diff --git a/patches/server/0019-Rewrite-chunk-system.patch b/patches/server/0019-Rewrite-chunk-system.patch index c3959dbe25..37fac792c1 100644 --- a/patches/server/0019-Rewrite-chunk-system.patch +++ b/patches/server/0019-Rewrite-chunk-system.patch @@ -3,6 +3,79 @@ From: Spottedleaf Date: Thu, 11 Mar 2021 02:32:30 -0800 Subject: [PATCH] Rewrite chunk system +Rebased patches: + +New player chunk loader system + +Make ChunkStatus.EMPTY not rely on the main thread for completion + +In order to do this, we need to push the POI consistency checks +to a later status. Since FULL is the only other status that +uses the main thread, it can go there. + +The consistency checks are only really for when a desync occurs, +and so that delaying the check only matters when the chunk data +has desync'd. As long as the desync is sorted before the +chunk is full loaded (i.e before setBlock can occur on +a chunk), it should not matter. + +This change is primarily due to behavioural changes +in the chunk task queue brought by region threading - +which is to split the queue into separate regions. As such, +it is required that in order for the sync load to complete +that the region owning the chunk drain and execute the task +while ticking. However, that is not always possible in +region threading. Thus, removing the main thread reliance allows +the chunk to progress without requiring a tick thread. +Specifically, this allows far sync loads (outside of a specific +regions bounds) to occur without issue - namely with structure +searching. + +Increase parallelism for neighbour writing chunk statuses + +Namely, everything after FEATURES. By creating a dependency +chain indicating what chunks are in use, we can safely +schedule completely independent tasks in parallel. This +will allow the chunk system to scale beyond 10 threads +per world. + +Properly cancel chunk load tasks that were not scheduled + +Since the chunk load task was not scheduled, the entity/poi load +task fields will not be set, but the task complete counter +will not be adjusted. Thus, the chunk load task will not complete. + +To resolve this, detect when the entity/poi tasks were not scheduled +and decrement the task complete counter in such cases. + +Mark POI/Entity load tasks as completed before releasing scheduling lock + +It must be marked as completed during that lock hold since the +waiters field is set to null. Thus, any other thread attempting +a cancellation will fail to remove from waiters. Also, any +other thread attempting to cancel may set the completed field +to true which would cause accept() to fail as well. + +Completion was always designed to happen while holding the +scheduling lock to prevent these race conditions. The code +was originally set up to complete while not holding the +scheduling lock to avoid invoking callbacks while holding the +lock, however the access to the completion field was not +considered. + +Resolve this by marking the callback as completed during the +lock, but invoking the accept() function after releasing +the lock. This will prevent any cancellation attempts to be +blocked, and allow the current thread to complete the callback +without any issues. + +Cache whether region files do not exist + +The repeated I/O of creating the directory for the regionfile +or for checking if the file exists can be heavy in +when pushing chunk generation extremely hard - as each chunk gen +request may effectively go through to the I/O thread. + == AT == public net.minecraft.server.level.ChunkMap setViewDistance(I)V public net.minecraft.server.level.ChunkHolder pos @@ -138,7 +211,7 @@ index 146c78a333e47cb4d8aa97700e19a12ca176ce76..691239e65b0870ceb0d071b57793cff9 protected static final class LightQueue { diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java -index 38f01952153348d937e326da0ec102cd9b0f80af..43380d5e3a40b64bebdf3c0e7c48eca8998c8ac0 100644 +index 38f01952153348d937e326da0ec102cd9b0f80af..1080e1f67afe5574baca0df50cdb1d029a7a586a 100644 --- a/src/main/java/co/aikar/timings/TimingsExport.java +++ b/src/main/java/co/aikar/timings/TimingsExport.java @@ -163,7 +163,11 @@ public class TimingsExport extends Thread { @@ -147,9 +220,9 @@ index 38f01952153348d937e326da0ec102cd9b0f80af..43380d5e3a40b64bebdf3c0e7c48eca8 })), - pair("ticking-distance", world.getChunkSource().chunkMap.getEffectiveViewDistance()) + // Paper start - replace chunk loader system -+ pair("ticking-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance()), -+ pair("no-ticking-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance()), -+ pair("sending-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetSendDistance()) ++ pair("ticking-distance", world.getWorld().getSimulationDistance()), ++ pair("no-ticking-distance", world.getWorld().getViewDistance()), ++ pair("sending-distance", world.getWorld().getSendViewDistance()) + // Paper end - replace chunk loader system )); })); @@ -1309,10 +1382,10 @@ index 0000000000000000000000000000000000000000..99f49b5625cf51d6c97640553cf5c420 +} diff --git a/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java new file mode 100644 -index 0000000000000000000000000000000000000000..e77972c4c264100ffdd824bfa2dac58dbbc6d678 +index 0000000000000000000000000000000000000000..562630db2cf5f923bf5b611b828a365e6d60fefb --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java -@@ -0,0 +1,1128 @@ +@@ -0,0 +1,1113 @@ +package io.papermc.paper.chunk; + +import com.destroystokyo.paper.util.misc.PlayerAreaMap; @@ -1356,12 +1429,7 @@ index 0000000000000000000000000000000000000000..e77972c4c264100ffdd824bfa2dac58d + } + + public static int getTickViewDistance(final ServerPlayer player) { -+ final ServerLevel level = (ServerLevel)player.level; -+ final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player); -+ if (data == null) { -+ return level.chunkSource.chunkMap.playerChunkManager.getTargetTickViewDistance(); -+ } -+ return data.getTargetTickViewDistance(); ++ throw new UnsupportedOperationException(); + } + + public static int getLoadViewDistance(final Player player) { @@ -1369,12 +1437,7 @@ index 0000000000000000000000000000000000000000..e77972c4c264100ffdd824bfa2dac58d + } + + public static int getLoadViewDistance(final ServerPlayer player) { -+ final ServerLevel level = (ServerLevel)player.level; -+ final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player); -+ if (data == null) { -+ return level.chunkSource.chunkMap.playerChunkManager.getLoadDistance(); -+ } -+ return data.getLoadDistance(); ++ throw new UnsupportedOperationException(); + } + + public static int getSendViewDistance(final Player player) { @@ -1382,12 +1445,7 @@ index 0000000000000000000000000000000000000000..e77972c4c264100ffdd824bfa2dac58d + } + + public static int getSendViewDistance(final ServerPlayer player) { -+ final ServerLevel level = (ServerLevel)player.level; -+ final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player); -+ if (data == null) { -+ return level.chunkSource.chunkMap.playerChunkManager.getTargetSendDistance(); -+ } -+ return data.getTargetSendViewDistance(); ++ throw new UnsupportedOperationException(); + } + + protected final ChunkMap chunkMap; @@ -2187,7 +2245,7 @@ index 0000000000000000000000000000000000000000..e77972c4c264100ffdd824bfa2dac58d + + public void sendChunk(final int chunkX, final int chunkZ, final Runnable onChunkSend) { + if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -+ this.player.getLevel().getChunkSource().chunkMap.updateChunkTracking(this.player, ++ ((ServerLevel)this.player.level()).getChunkSource().chunkMap.updateChunkTracking(this.player, + new ChunkPos(chunkX, chunkZ), new MutableObject<>(), false, true); // unloaded, loaded + this.player.connection.connection.execute(onChunkSend); + } else { @@ -2197,7 +2255,7 @@ index 0000000000000000000000000000000000000000..e77972c4c264100ffdd824bfa2dac58d + + public void unloadChunk(final int chunkX, final int chunkZ) { + if (this.sentChunks.remove(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -+ this.player.getLevel().getChunkSource().chunkMap.updateChunkTracking(this.player, ++ ((ServerLevel)this.player.level()).getChunkSource().chunkMap.updateChunkTracking(this.player, + new ChunkPos(chunkX, chunkZ), null, true, false); // unloaded, loaded + } + } @@ -2442,7 +2500,7 @@ index 0000000000000000000000000000000000000000..e77972c4c264100ffdd824bfa2dac58d + } +} diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java -index 8a5e93961dac4d87c81c0e70b6f4124a1f1d2556..0dc94dec1317b3f86d38074c6cbe41ab828cab1d 100644 +index 8a5e93961dac4d87c81c0e70b6f4124a1f1d2556..97edd4e8d3524c839a1765b6515deacae112ff4b 100644 --- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java @@ -31,191 +31,41 @@ public final class ChunkSystem { @@ -2651,7 +2709,7 @@ index 8a5e93961dac4d87c81c0e70b6f4124a1f1d2556..0dc94dec1317b3f86d38074c6cbe41ab public static int getSendViewDistance(final ServerPlayer player) { - return getLoadViewDistance(player); -+ return io.papermc.paper.chunk.PlayerChunkLoader.getSendViewDistance(player); ++ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPISendViewDistance(player); } public static int getLoadViewDistance(final ServerPlayer player) { @@ -2660,7 +2718,7 @@ index 8a5e93961dac4d87c81c0e70b6f4124a1f1d2556..0dc94dec1317b3f86d38074c6cbe41ab - return Bukkit.getViewDistance() + 1; - } - return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1; -+ return io.papermc.paper.chunk.PlayerChunkLoader.getLoadViewDistance(player); ++ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getLoadViewDistance(player); } public static int getTickViewDistance(final ServerPlayer player) { @@ -2669,10 +2727,1433 @@ index 8a5e93961dac4d87c81c0e70b6f4124a1f1d2556..0dc94dec1317b3f86d38074c6cbe41ab - return Bukkit.getSimulationDistance(); - } - return level.chunkSource.chunkMap.distanceManager.getSimulationDistance(); -+ return io.papermc.paper.chunk.PlayerChunkLoader.getTickViewDistance(player); ++ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPITickViewDistance(player); } private ChunkSystem() { +diff --git a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java +new file mode 100644 +index 0000000000000000000000000000000000000000..48bfee5b9db501fcdba4ddb1e4bff2718956a680 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java +@@ -0,0 +1,1417 @@ ++package io.papermc.paper.chunk.system; ++ ++import ca.spottedleaf.concurrentutil.collection.SRSWLinkedQueue; ++import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; ++import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import io.papermc.paper.chunk.system.io.RegionFileIOThread; ++import io.papermc.paper.chunk.system.scheduling.ChunkHolderManager; ++import io.papermc.paper.configuration.GlobalConfiguration; ++import io.papermc.paper.util.CoordinateUtils; ++import io.papermc.paper.util.IntegerUtil; ++import io.papermc.paper.util.TickThread; ++import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; ++import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; ++import it.unimi.dsi.fastutil.longs.LongArrayList; ++import it.unimi.dsi.fastutil.longs.LongComparator; ++import it.unimi.dsi.fastutil.longs.LongHeapPriorityQueue; ++import it.unimi.dsi.fastutil.longs.LongOpenHashSet; ++import net.minecraft.network.protocol.Packet; ++import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket; ++import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket; ++import net.minecraft.network.protocol.game.ClientboundSetSimulationDistancePacket; ++import net.minecraft.server.level.ChunkMap; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.server.level.TicketType; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.GameRules; ++import net.minecraft.world.level.chunk.ChunkAccess; ++import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.LevelChunk; ++import net.minecraft.world.level.levelgen.BelowZeroRetrogen; ++import org.apache.commons.lang3.mutable.MutableObject; ++import org.bukkit.craftbukkit.entity.CraftPlayer; ++import org.bukkit.entity.Player; ++import java.lang.invoke.VarHandle; ++import java.util.ArrayDeque; ++import java.util.concurrent.TimeUnit; ++import java.util.concurrent.atomic.AtomicLong; ++ ++public class RegionizedPlayerChunkLoader { ++ ++ public static final TicketType REGION_PLAYER_TICKET = TicketType.create("region_player_ticket", Long::compareTo); ++ ++ public static final int MIN_VIEW_DISTANCE = 2; ++ public static final int MAX_VIEW_DISTANCE = 32; ++ ++ public static final int TICK_TICKET_LEVEL = 31; ++ public static final int GENERATED_TICKET_LEVEL = 33 + ChunkStatus.getDistance(ChunkStatus.FULL); ++ public static final int LOADED_TICKET_LEVEL = 33 + ChunkStatus.getDistance(ChunkStatus.EMPTY); ++ ++ public static final record ViewDistances( ++ int tickViewDistance, ++ int loadViewDistance, ++ int sendViewDistance ++ ) { ++ public ViewDistances setTickViewDistance(final int distance) { ++ return new ViewDistances(distance, this.loadViewDistance, this.sendViewDistance); ++ } ++ ++ public ViewDistances setLoadViewDistance(final int distance) { ++ return new ViewDistances(this.tickViewDistance, distance, this.sendViewDistance); ++ } ++ ++ ++ public ViewDistances setSendViewDistance(final int distance) { ++ return new ViewDistances(this.tickViewDistance, this.loadViewDistance, distance); ++ } ++ } ++ ++ public static int getAPITickViewDistance(final Player player) { ++ return getAPITickViewDistance(((CraftPlayer)player).getHandle()); ++ } ++ ++ public static int getAPITickViewDistance(final ServerPlayer player) { ++ final ServerLevel level = (ServerLevel)player.level(); ++ final PlayerChunkLoaderData data = player.chunkLoader; ++ if (data == null) { ++ return level.playerChunkLoader.getAPITickDistance(); ++ } ++ return data.lastTickDistance; ++ } ++ ++ public static int getAPIViewDistance(final Player player) { ++ return getAPIViewDistance(((CraftPlayer)player).getHandle()); ++ } ++ ++ public static int getAPIViewDistance(final ServerPlayer player) { ++ final ServerLevel level = (ServerLevel)player.level(); ++ final PlayerChunkLoaderData data = player.chunkLoader; ++ if (data == null) { ++ return level.playerChunkLoader.getAPIViewDistance(); ++ } ++ // view distance = load distance + 1 ++ return data.lastLoadDistance - 1; ++ } ++ ++ public static int getLoadViewDistance(final ServerPlayer player) { ++ final ServerLevel level = (ServerLevel)player.level(); ++ final PlayerChunkLoaderData data = player.chunkLoader; ++ if (data == null) { ++ return level.playerChunkLoader.getAPIViewDistance(); ++ } ++ // view distance = load distance + 1 ++ return data.lastLoadDistance - 1; ++ } ++ ++ public static int getAPISendViewDistance(final Player player) { ++ return getAPISendViewDistance(((CraftPlayer)player).getHandle()); ++ } ++ ++ public static int getAPISendViewDistance(final ServerPlayer player) { ++ final ServerLevel level = (ServerLevel)player.level(); ++ final PlayerChunkLoaderData data = player.chunkLoader; ++ if (data == null) { ++ return level.playerChunkLoader.getAPISendViewDistance(); ++ } ++ return data.lastSendDistance; ++ } ++ ++ private final ServerLevel world; ++ ++ public RegionizedPlayerChunkLoader(final ServerLevel world) { ++ this.world = world; ++ } ++ ++ public void addPlayer(final ServerPlayer player) { ++ TickThread.ensureTickThread(player, "Cannot add player to player chunk loader async"); ++ if (!player.isRealPlayer) { ++ return; ++ } ++ ++ if (player.chunkLoader != null) { ++ throw new IllegalStateException("Player is already added to player chunk loader"); ++ } ++ ++ final PlayerChunkLoaderData loader = new PlayerChunkLoaderData(this.world, player); ++ ++ player.chunkLoader = loader; ++ loader.add(); ++ } ++ ++ public void updatePlayer(final ServerPlayer player) { ++ final PlayerChunkLoaderData loader = player.chunkLoader; ++ if (loader != null) { ++ loader.update(); ++ } ++ } ++ ++ public void removePlayer(final ServerPlayer player) { ++ TickThread.ensureTickThread(player, "Cannot remove player from player chunk loader async"); ++ if (!player.isRealPlayer) { ++ return; ++ } ++ ++ final PlayerChunkLoaderData loader = player.chunkLoader; ++ ++ if (loader == null) { ++ throw new IllegalStateException("Player is already removed from player chunk loader"); ++ } ++ ++ loader.remove(); ++ player.chunkLoader = null; ++ } ++ ++ public void setSendDistance(final int distance) { ++ this.world.setSendViewDistance(distance); ++ } ++ ++ public void setLoadDistance(final int distance) { ++ this.world.setLoadViewDistance(distance); ++ } ++ ++ public void setTickDistance(final int distance) { ++ this.world.setTickViewDistance(distance); ++ } ++ ++ // Note: follow the player chunk loader so everything stays consistent... ++ public int getAPITickDistance() { ++ final ViewDistances distances = this.world.getViewDistances(); ++ final int tickViewDistance = PlayerChunkLoaderData.getTickDistance(-1, distances.tickViewDistance); ++ return tickViewDistance; ++ } ++ ++ public int getAPIViewDistance() { ++ final ViewDistances distances = this.world.getViewDistances(); ++ final int tickViewDistance = PlayerChunkLoaderData.getTickDistance(-1, distances.tickViewDistance); ++ final int loadDistance = PlayerChunkLoaderData.getLoadViewDistance(tickViewDistance, -1, distances.loadViewDistance); ++ ++ // loadDistance = api view distance + 1 ++ return loadDistance - 1; ++ } ++ ++ public int getAPISendViewDistance() { ++ final ViewDistances distances = this.world.getViewDistances(); ++ final int tickViewDistance = PlayerChunkLoaderData.getTickDistance(-1, distances.tickViewDistance); ++ final int loadDistance = PlayerChunkLoaderData.getLoadViewDistance(tickViewDistance, -1, distances.loadViewDistance); ++ final int sendViewDistance = PlayerChunkLoaderData.getSendViewDistance( ++ loadDistance, -1, -1, distances.sendViewDistance ++ ); ++ ++ return sendViewDistance; ++ } ++ ++ public boolean isChunkSent(final ServerPlayer player, final int chunkX, final int chunkZ, final boolean borderOnly) { ++ return borderOnly ? this.isChunkSentBorderOnly(player, chunkX, chunkZ) : this.isChunkSent(player, chunkX, chunkZ); ++ } ++ ++ public boolean isChunkSent(final ServerPlayer player, final int chunkX, final int chunkZ) { ++ final PlayerChunkLoaderData loader = player.chunkLoader; ++ if (loader == null) { ++ return false; ++ } ++ ++ return loader.sentChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ)); ++ } ++ ++ public boolean isChunkSentBorderOnly(final ServerPlayer player, final int chunkX, final int chunkZ) { ++ final PlayerChunkLoaderData loader = player.chunkLoader; ++ if (loader == null) { ++ return false; ++ } ++ ++ for (int dz = -1; dz <= 1; ++dz) { ++ for (int dx = -1; dx <= 1; ++dx) { ++ if (!loader.sentChunks.contains(CoordinateUtils.getChunkKey(dx + chunkX, dz + chunkZ))) { ++ return true; ++ } ++ } ++ } ++ ++ return false; ++ } ++ ++ public void tick() { ++ TickThread.ensureTickThread("Cannot tick player chunk loader async"); ++ long currTime = System.nanoTime(); ++ for (final ServerPlayer player : new java.util.ArrayList<>(this.world.players())) { ++ final PlayerChunkLoaderData loader = player.chunkLoader; ++ if (loader == null || loader.world != this.world) { ++ // not our problem anymore ++ continue; ++ } ++ loader.update(); // can't invoke plugin logic ++ loader.updateQueues(currTime); ++ } ++ } ++ ++ private static long[] generateBFSOrder(final int radius) { ++ final LongArrayList chunks = new LongArrayList(); ++ final LongArrayFIFOQueue queue = new LongArrayFIFOQueue(); ++ final LongOpenHashSet seen = new LongOpenHashSet(); ++ ++ seen.add(CoordinateUtils.getChunkKey(0, 0)); ++ queue.enqueue(CoordinateUtils.getChunkKey(0, 0)); ++ while (!queue.isEmpty()) { ++ final long chunk = queue.dequeueLong(); ++ final int chunkX = CoordinateUtils.getChunkX(chunk); ++ final int chunkZ = CoordinateUtils.getChunkZ(chunk); ++ ++ // important that the addition to the list is here, rather than when enqueueing neighbours ++ // ensures the order is actually kept ++ chunks.add(chunk); ++ ++ // -x ++ final long n1 = CoordinateUtils.getChunkKey(chunkX - 1, chunkZ); ++ // -z ++ final long n2 = CoordinateUtils.getChunkKey(chunkX, chunkZ - 1); ++ // +x ++ final long n3 = CoordinateUtils.getChunkKey(chunkX + 1, chunkZ); ++ // +z ++ final long n4 = CoordinateUtils.getChunkKey(chunkX, chunkZ + 1); ++ ++ final long[] list = new long[] {n1, n2, n3, n4}; ++ ++ for (final long neighbour : list) { ++ final int neighbourX = CoordinateUtils.getChunkX(neighbour); ++ final int neighbourZ = CoordinateUtils.getChunkZ(neighbour); ++ if (Math.max(Math.abs(neighbourX), Math.abs(neighbourZ)) > radius) { ++ // don't enqueue out of range ++ continue; ++ } ++ if (!seen.add(neighbour)) { ++ continue; ++ } ++ queue.enqueue(neighbour); ++ } ++ } ++ ++ // to increase generation parallelism, we want to space the chunks out so that they are not nearby when generating ++ // this also means we are minimising locality ++ // but, we need to maintain sorted order by manhatten distance ++ ++ // first, build a map of manhatten distance -> chunks ++ final java.util.List byDistance = new java.util.ArrayList<>(); ++ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator = chunks.iterator(); iterator.hasNext();) { ++ final long chunkKey = iterator.nextLong(); ++ ++ final int chunkX = CoordinateUtils.getChunkX(chunkKey); ++ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey); ++ ++ final int dist = Math.abs(chunkX) + Math.abs(chunkZ); ++ if (dist == byDistance.size()) { ++ final LongArrayList list = new LongArrayList(); ++ list.add(chunkKey); ++ byDistance.add(list); ++ continue; ++ } ++ ++ byDistance.get(dist).add(chunkKey); ++ } ++ ++ // per distance we transform the chunk list so that each element is maximally spaced out from each other ++ for (int i = 0, len = byDistance.size(); i < len; ++i) { ++ final LongArrayList notAdded = byDistance.get(i).clone(); ++ final LongArrayList added = new LongArrayList(); ++ ++ while (!notAdded.isEmpty()) { ++ if (added.isEmpty()) { ++ added.add(notAdded.removeLong(notAdded.size() - 1)); ++ continue; ++ } ++ ++ long maxChunk = -1L; ++ int maxDist = 0; ++ ++ // select the chunk from the not yet added set that has the largest minimum distance from ++ // the current set of added chunks ++ ++ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator = notAdded.iterator(); iterator.hasNext();) { ++ final long chunkKey = iterator.nextLong(); ++ final int chunkX = CoordinateUtils.getChunkX(chunkKey); ++ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey); ++ ++ int minDist = Integer.MAX_VALUE; ++ ++ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator2 = added.iterator(); iterator2.hasNext();) { ++ final long addedKey = iterator2.nextLong(); ++ final int addedX = CoordinateUtils.getChunkX(addedKey); ++ final int addedZ = CoordinateUtils.getChunkZ(addedKey); ++ ++ // here we use square distance because chunk generation uses neighbours in a square radius ++ final int dist = Math.max(Math.abs(addedX - chunkX), Math.abs(addedZ - chunkZ)); ++ ++ if (dist < minDist) { ++ minDist = dist; ++ } ++ } ++ ++ if (minDist > maxDist) { ++ maxDist = minDist; ++ maxChunk = chunkKey; ++ } ++ } ++ ++ // move the selected chunk from the not added set to the added set ++ ++ if (!notAdded.rem(maxChunk)) { ++ throw new IllegalStateException(); ++ } ++ ++ added.add(maxChunk); ++ } ++ ++ byDistance.set(i, added); ++ } ++ ++ // now, rebuild the list so that it still maintains manhatten distance order ++ final LongArrayList ret = new LongArrayList(chunks.size()); ++ ++ for (final LongArrayList dist : byDistance) { ++ ret.addAll(dist); ++ } ++ ++ return ret.toLongArray(); ++ } ++ ++ public static final class PlayerChunkLoaderData { ++ ++ private static final AtomicLong ID_GENERATOR = new AtomicLong(); ++ private final long id = ID_GENERATOR.incrementAndGet(); ++ private final Long idBoxed = Long.valueOf(this.id); ++ ++ // expected that this list returns for a given radius, the set of chunks ordered ++ // by manhattan distance ++ private static final long[][] SEARCH_RADIUS_ITERATION_LIST = new long[65][]; ++ static { ++ for (int i = 0; i < SEARCH_RADIUS_ITERATION_LIST.length; ++i) { ++ // a BFS around -x, -z, +x, +z will give increasing manhatten distance ++ SEARCH_RADIUS_ITERATION_LIST[i] = generateBFSOrder(i); ++ } ++ } ++ ++ private static final long MAX_RATE = 10_000L; ++ ++ private final ServerPlayer player; ++ private final ServerLevel world; ++ ++ private int lastChunkX = Integer.MIN_VALUE; ++ private int lastChunkZ = Integer.MIN_VALUE; ++ ++ private int lastSendDistance = Integer.MIN_VALUE; ++ private int lastLoadDistance = Integer.MIN_VALUE; ++ private int lastTickDistance = Integer.MIN_VALUE; ++ ++ private int lastSentChunkCenterX = Integer.MIN_VALUE; ++ private int lastSentChunkCenterZ = Integer.MIN_VALUE; ++ ++ private int lastSentChunkRadius = Integer.MIN_VALUE; ++ private int lastSentSimulationDistance = Integer.MIN_VALUE; ++ ++ private boolean canGenerateChunks = true; ++ ++ private final ArrayDeque> delayedTicketOps = new ArrayDeque<>(); ++ private final LongOpenHashSet sentChunks = new LongOpenHashSet(); ++ ++ private static final byte CHUNK_TICKET_STAGE_NONE = 0; ++ private static final byte CHUNK_TICKET_STAGE_LOADING = 1; ++ private static final byte CHUNK_TICKET_STAGE_LOADED = 2; ++ private static final byte CHUNK_TICKET_STAGE_GENERATING = 3; ++ private static final byte CHUNK_TICKET_STAGE_GENERATED = 4; ++ private static final byte CHUNK_TICKET_STAGE_TICK = 5; ++ private static final int[] TICKET_STAGE_TO_LEVEL = new int[] { ++ ChunkHolderManager.MAX_TICKET_LEVEL + 1, ++ LOADED_TICKET_LEVEL, ++ LOADED_TICKET_LEVEL, ++ GENERATED_TICKET_LEVEL, ++ GENERATED_TICKET_LEVEL, ++ TICK_TICKET_LEVEL ++ }; ++ private final Long2ByteOpenHashMap chunkTicketStage = new Long2ByteOpenHashMap(); ++ { ++ this.chunkTicketStage.defaultReturnValue(CHUNK_TICKET_STAGE_NONE); ++ } ++ ++ // rate limiting ++ private final AllocatingRateLimiter chunkSendLimiter = new AllocatingRateLimiter(); ++ private final AllocatingRateLimiter chunkLoadTicketLimiter = new AllocatingRateLimiter(); ++ private final AllocatingRateLimiter chunkGenerateTicketLimiter = new AllocatingRateLimiter(); ++ ++ // queues ++ private final LongComparator CLOSEST_MANHATTAN_DIST = (final long c1, final long c2) -> { ++ final int c1x = CoordinateUtils.getChunkX(c1); ++ final int c1z = CoordinateUtils.getChunkZ(c1); ++ ++ final int c2x = CoordinateUtils.getChunkX(c2); ++ final int c2z = CoordinateUtils.getChunkZ(c2); ++ ++ final int centerX = PlayerChunkLoaderData.this.lastChunkX; ++ final int centerZ = PlayerChunkLoaderData.this.lastChunkZ; ++ ++ return Integer.compare( ++ Math.abs(c1x - centerX) + Math.abs(c1z - centerZ), ++ Math.abs(c2x - centerX) + Math.abs(c2z - centerZ) ++ ); ++ }; ++ private final LongHeapPriorityQueue sendQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); ++ private final LongHeapPriorityQueue tickingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); ++ private final LongHeapPriorityQueue generatingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); ++ private final LongHeapPriorityQueue genQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); ++ private final LongHeapPriorityQueue loadingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); ++ private final LongHeapPriorityQueue loadQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); ++ ++ private volatile boolean removed; ++ ++ public PlayerChunkLoaderData(final ServerLevel world, final ServerPlayer player) { ++ this.world = world; ++ this.player = player; ++ } ++ ++ private void flushDelayedTicketOps() { ++ if (this.delayedTicketOps.isEmpty()) { ++ return; ++ } ++ this.world.chunkTaskScheduler.chunkHolderManager.pushDelayedTicketUpdates(this.delayedTicketOps); ++ this.delayedTicketOps.clear(); ++ this.world.chunkTaskScheduler.chunkHolderManager.tryDrainTicketUpdates(); ++ } ++ ++ private void pushDelayedTicketOp(final ChunkHolderManager.TicketOperation op) { ++ this.delayedTicketOps.addLast(op); ++ } ++ ++ private void sendChunk(final int chunkX, final int chunkZ) { ++ if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { ++ this.world.getChunkSource().chunkMap.updateChunkTracking(this.player, ++ new ChunkPos(chunkX, chunkZ), new MutableObject<>(), false, true); // unloaded, loaded ++ return; ++ } ++ throw new IllegalStateException(); ++ } ++ ++ private void sendUnloadChunk(final int chunkX, final int chunkZ) { ++ if (!this.sentChunks.remove(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { ++ return; ++ } ++ this.sendUnloadChunkRaw(chunkX, chunkZ); ++ } ++ ++ private void sendUnloadChunkRaw(final int chunkX, final int chunkZ) { ++ this.player.serverLevel().getChunkSource().chunkMap.updateChunkTracking(this.player, ++ new ChunkPos(chunkX, chunkZ), null, true, false); // unloaded, loaded ++ } ++ ++ private final SingleUserAreaMap broadcastMap = new SingleUserAreaMap<>(this) { ++ @Override ++ protected void addCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { ++ // do nothing, we only care about remove ++ } ++ ++ @Override ++ protected void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { ++ parameter.sendUnloadChunk(chunkX, chunkZ); ++ } ++ }; ++ private final SingleUserAreaMap loadTicketCleanup = new SingleUserAreaMap<>(this) { ++ @Override ++ protected void addCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { ++ // do nothing, we only care about remove ++ } ++ ++ @Override ++ protected void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { ++ final long chunk = CoordinateUtils.getChunkKey(chunkX, chunkZ); ++ final byte ticketStage = parameter.chunkTicketStage.remove(chunk); ++ final int level = TICKET_STAGE_TO_LEVEL[ticketStage]; ++ if (level > ChunkHolderManager.MAX_TICKET_LEVEL) { ++ return; ++ } ++ ++ parameter.pushDelayedTicketOp(ChunkHolderManager.TicketOperation.addAndRemove( ++ chunk, ++ TicketType.UNKNOWN, level, new ChunkPos(chunkX, chunkZ), ++ REGION_PLAYER_TICKET, level, parameter.idBoxed ++ )); ++ } ++ }; ++ private final SingleUserAreaMap tickMap = new SingleUserAreaMap<>(this) { ++ @Override ++ protected void addCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { ++ // do nothing, we will detect ticking chunks when we try to load them ++ } ++ ++ @Override ++ protected void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { ++ final long chunk = CoordinateUtils.getChunkKey(chunkX, chunkZ); ++ // note: by the time this is called, the tick cleanup should have ran - so, if the chunk is at ++ // the tick stage it was deemed in range for loading. Thus, we need to move it to generated ++ if (!parameter.chunkTicketStage.replace(chunk, CHUNK_TICKET_STAGE_TICK, CHUNK_TICKET_STAGE_GENERATED)) { ++ return; ++ } ++ ++ // Since we are possibly downgrading the ticket level, we add an unknown ticket so that ++ // the level is kept until tick(). ++ parameter.pushDelayedTicketOp(ChunkHolderManager.TicketOperation.addAndRemove( ++ chunk, ++ TicketType.UNKNOWN, TICK_TICKET_LEVEL, new ChunkPos(chunkX, chunkZ), ++ REGION_PLAYER_TICKET, TICK_TICKET_LEVEL, parameter.idBoxed ++ )); ++ // keep chunk at new generated level ++ parameter.pushDelayedTicketOp(ChunkHolderManager.TicketOperation.addOp( ++ chunk, ++ REGION_PLAYER_TICKET, GENERATED_TICKET_LEVEL, parameter.idBoxed ++ )); ++ } ++ }; ++ ++ private static boolean wantChunkLoaded(final int centerX, final int centerZ, final int chunkX, final int chunkZ, ++ final int sendRadius) { ++ // expect sendRadius to be = 1 + target viewable radius ++ return ChunkMap.isChunkInRange(chunkX, chunkZ, centerX, centerZ, sendRadius); ++ } ++ ++ private static int getClientViewDistance(final ServerPlayer player) { ++ final Integer vd = player.clientViewDistance; ++ return vd == null ? -1 : Math.max(0, vd.intValue()); ++ } ++ ++ private static int getTickDistance(final int playerTickViewDistance, final int worldTickViewDistance) { ++ return playerTickViewDistance < 0 ? worldTickViewDistance : playerTickViewDistance; ++ } ++ ++ private static int getLoadViewDistance(final int tickViewDistance, final int playerLoadViewDistance, ++ final int worldLoadViewDistance) { ++ return Math.max(tickViewDistance, playerLoadViewDistance < 0 ? worldLoadViewDistance : playerLoadViewDistance); ++ } ++ ++ private static int getSendViewDistance(final int loadViewDistance, final int clientViewDistance, ++ final int playerSendViewDistance, final int worldSendViewDistance) { ++ return Math.min( ++ loadViewDistance, ++ playerSendViewDistance < 0 ? (!GlobalConfiguration.get().chunkLoadingAdvanced.autoConfigSendDistance || clientViewDistance < 0 ? (worldSendViewDistance < 0 ? loadViewDistance : worldSendViewDistance) : clientViewDistance) : playerSendViewDistance ++ ); ++ } ++ ++ private Packet updateClientChunkRadius(final int radius) { ++ this.lastSentChunkRadius = radius; ++ return new ClientboundSetChunkCacheRadiusPacket(radius); ++ } ++ ++ private Packet updateClientSimulationDistance(final int distance) { ++ this.lastSentSimulationDistance = distance; ++ return new ClientboundSetSimulationDistancePacket(distance); ++ } ++ ++ private Packet updateClientChunkCenter(final int chunkX, final int chunkZ) { ++ this.lastSentChunkCenterX = chunkX; ++ this.lastSentChunkCenterZ = chunkZ; ++ return new ClientboundSetChunkCacheCenterPacket(chunkX, chunkZ); ++ } ++ ++ private boolean canPlayerGenerateChunks() { ++ return !this.player.isSpectator() || this.world.getGameRules().getBoolean(GameRules.RULE_SPECTATORSGENERATECHUNKS); ++ } ++ ++ private double getMaxChunkLoadRate() { ++ final double configRate = GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkLoadRate; ++ ++ return configRate < 0.0 || configRate > (double)MAX_RATE ? (double)MAX_RATE : Math.max(1.0, configRate); ++ } ++ ++ private double getMaxChunkGenRate() { ++ final double configRate = GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkGenerateRate; ++ ++ return configRate < 0.0 || configRate > (double)MAX_RATE ? (double)MAX_RATE : Math.max(1.0, configRate); ++ } ++ ++ private double getMaxChunkSendRate() { ++ final double configRate = GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkSendRate; ++ ++ return configRate < 0.0 || configRate > (double)MAX_RATE ? (double)MAX_RATE : Math.max(1.0, configRate); ++ } ++ ++ private long getMaxChunkLoads() { ++ final long radiusChunks = (2L * this.lastLoadDistance + 1L) * (2L * this.lastLoadDistance + 1L); ++ long configLimit = GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkLoads; ++ if (configLimit == 0L) { ++ // by default, only allow 1/5th of the chunks in the view distance to be concurrently active ++ configLimit = Math.max(5L, radiusChunks / 5L); ++ } else if (configLimit < 0L) { ++ configLimit = Integer.MAX_VALUE; ++ } // else: use the value configured ++ configLimit = configLimit - this.loadingQueue.size(); ++ ++ return configLimit; ++ } ++ ++ private long getMaxChunkGenerates() { ++ final long radiusChunks = (2L * this.lastLoadDistance + 1L) * (2L * this.lastLoadDistance + 1L); ++ long configLimit = GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkGenerates; ++ if (configLimit == 0L) { ++ // by default, only allow 1/5th of the chunks in the view distance to be concurrently active ++ configLimit = Math.max(5L, radiusChunks / 5L); ++ } else if (configLimit < 0L) { ++ configLimit = Integer.MAX_VALUE; ++ } // else: use the value configured ++ configLimit = configLimit - this.generatingQueue.size(); ++ ++ return configLimit; ++ } ++ ++ private boolean wantChunkSent(final int chunkX, final int chunkZ) { ++ final int dx = this.lastChunkX - chunkX; ++ final int dz = this.lastChunkZ - chunkZ; ++ return Math.max(Math.abs(dx), Math.abs(dz)) <= this.lastSendDistance && wantChunkLoaded( ++ this.lastChunkX, this.lastChunkZ, chunkX, chunkZ, this.lastSendDistance ++ ); ++ } ++ ++ private boolean wantChunkTicked(final int chunkX, final int chunkZ) { ++ final int dx = this.lastChunkX - chunkX; ++ final int dz = this.lastChunkZ - chunkZ; ++ return Math.max(Math.abs(dx), Math.abs(dz)) <= this.lastTickDistance; ++ } ++ ++ void updateQueues(final long time) { ++ TickThread.ensureTickThread(this.player, "Cannot tick player chunk loader async"); ++ if (this.removed) { ++ throw new IllegalStateException("Ticking removed player chunk loader"); ++ } ++ // update rate limits ++ final double loadRate = this.getMaxChunkLoadRate(); ++ final double genRate = this.getMaxChunkGenRate(); ++ final double sendRate = this.getMaxChunkSendRate(); ++ ++ this.chunkLoadTicketLimiter.tickAllocation(time, loadRate, loadRate); ++ this.chunkGenerateTicketLimiter.tickAllocation(time, genRate, genRate); ++ this.chunkSendLimiter.tickAllocation(time, sendRate, sendRate); ++ ++ // try to progress chunk loads ++ while (!this.loadingQueue.isEmpty()) { ++ final long pendingLoadChunk = this.loadingQueue.firstLong(); ++ final int pendingChunkX = CoordinateUtils.getChunkX(pendingLoadChunk); ++ final int pendingChunkZ = CoordinateUtils.getChunkZ(pendingLoadChunk); ++ final ChunkAccess pending = this.world.chunkSource.getChunkAtImmediately(pendingChunkX, pendingChunkZ); ++ if (pending == null) { ++ // nothing to do here ++ break; ++ } ++ // chunk has loaded, so we can take it out of the queue ++ this.loadingQueue.dequeueLong(); ++ ++ // try to move to generate queue ++ final byte prev = this.chunkTicketStage.put(pendingLoadChunk, CHUNK_TICKET_STAGE_LOADED); ++ if (prev != CHUNK_TICKET_STAGE_LOADING) { ++ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_LOADING + ", not " + prev); ++ } ++ ++ if (this.canGenerateChunks || this.isLoadedChunkGeneratable(pending)) { ++ this.genQueue.enqueue(pendingLoadChunk); ++ } // else: don't want to generate, so just leave it loaded ++ } ++ ++ // try to push more chunk loads ++ final long maxLoads = Math.max(0L, Math.min(MAX_RATE, Math.min(this.loadQueue.size(), this.getMaxChunkLoads()))); ++ final int maxLoadsThisTick = (int)this.chunkLoadTicketLimiter.takeAllocation(time, loadRate, maxLoads); ++ if (maxLoadsThisTick > 0) { ++ final LongArrayList chunks = new LongArrayList(maxLoadsThisTick); ++ for (int i = 0; i < maxLoadsThisTick; ++i) { ++ final long chunk = this.loadQueue.dequeueLong(); ++ final byte prev = this.chunkTicketStage.put(chunk, CHUNK_TICKET_STAGE_LOADING); ++ if (prev != CHUNK_TICKET_STAGE_NONE) { ++ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_NONE + ", not " + prev); ++ } ++ this.pushDelayedTicketOp( ++ ChunkHolderManager.TicketOperation.addOp( ++ chunk, ++ REGION_PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed ++ ) ++ ); ++ chunks.add(chunk); ++ this.loadingQueue.enqueue(chunk); ++ } ++ ++ // here we need to flush tickets, as scheduleChunkLoad requires tickets to be propagated with addTicket = false ++ this.flushDelayedTicketOps(); ++ // we only need to call scheduleChunkLoad because the loaded ticket level is not enough to start the chunk ++ // load - only generate ticket levels start anything, but they start generation... ++ // propagate levels ++ // Note: this CAN call plugin logic, so it is VITAL that our bookkeeping logic is completely done by the time this is invoked ++ this.world.chunkTaskScheduler.chunkHolderManager.processTicketUpdates(); ++ ++ if (this.removed) { ++ // process ticket updates may invoke plugin logic, which may remove this player ++ return; ++ } ++ ++ for (int i = 0; i < maxLoadsThisTick; ++i) { ++ final long queuedLoadChunk = chunks.getLong(i); ++ final int queuedChunkX = CoordinateUtils.getChunkX(queuedLoadChunk); ++ final int queuedChunkZ = CoordinateUtils.getChunkZ(queuedLoadChunk); ++ this.world.chunkTaskScheduler.scheduleChunkLoad( ++ queuedChunkX, queuedChunkZ, ChunkStatus.EMPTY, false, PrioritisedExecutor.Priority.NORMAL, null ++ ); ++ if (this.removed) { ++ return; ++ } ++ } ++ } ++ ++ // try to progress chunk generations ++ while (!this.generatingQueue.isEmpty()) { ++ final long pendingGenChunk = this.generatingQueue.firstLong(); ++ final int pendingChunkX = CoordinateUtils.getChunkX(pendingGenChunk); ++ final int pendingChunkZ = CoordinateUtils.getChunkZ(pendingGenChunk); ++ final LevelChunk pending = this.world.chunkSource.getChunkAtIfLoadedMainThreadNoCache(pendingChunkX, pendingChunkZ); ++ if (pending == null) { ++ // nothing to do here ++ break; ++ } ++ ++ // chunk has generated, so we can take it out of queue ++ this.generatingQueue.dequeueLong(); ++ ++ final byte prev = this.chunkTicketStage.put(pendingGenChunk, CHUNK_TICKET_STAGE_GENERATED); ++ if (prev != CHUNK_TICKET_STAGE_GENERATING) { ++ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_GENERATING + ", not " + prev); ++ } ++ ++ // try to move to send queue ++ if (this.wantChunkSent(pendingChunkX, pendingChunkZ)) { ++ this.sendQueue.enqueue(pendingGenChunk); ++ } ++ // try to move to tick queue ++ if (this.wantChunkTicked(pendingChunkX, pendingChunkZ)) { ++ this.tickingQueue.enqueue(pendingGenChunk); ++ } ++ } ++ ++ // try to push more chunk generations ++ final long maxGens = Math.max(0L, Math.min(MAX_RATE, Math.min(this.genQueue.size(), this.getMaxChunkGenerates()))); ++ final int maxGensThisTick = (int)this.chunkGenerateTicketLimiter.takeAllocation(time, genRate, maxGens); ++ for (int i = 0; i < maxGensThisTick; ++i) { ++ final long chunk = this.genQueue.dequeueLong(); ++ final byte prev = this.chunkTicketStage.put(chunk, CHUNK_TICKET_STAGE_GENERATING); ++ if (prev != CHUNK_TICKET_STAGE_LOADED) { ++ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_LOADED + ", not " + prev); ++ } ++ this.pushDelayedTicketOp( ++ ChunkHolderManager.TicketOperation.addAndRemove( ++ chunk, ++ REGION_PLAYER_TICKET, GENERATED_TICKET_LEVEL, this.idBoxed, ++ REGION_PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed ++ ) ++ ); ++ this.generatingQueue.enqueue(chunk); ++ } ++ ++ // try to pull ticking chunks ++ tick_check_outer: ++ while (!this.tickingQueue.isEmpty()) { ++ final long pendingTicking = this.tickingQueue.firstLong(); ++ final int pendingChunkX = CoordinateUtils.getChunkX(pendingTicking); ++ final int pendingChunkZ = CoordinateUtils.getChunkZ(pendingTicking); ++ ++ final int tickingReq = 2; ++ for (int dz = -tickingReq; dz <= tickingReq; ++dz) { ++ for (int dx = -tickingReq; dx <= tickingReq; ++dx) { ++ if ((dx | dz) == 0) { ++ continue; ++ } ++ final long neighbour = CoordinateUtils.getChunkKey(dx + pendingChunkX, dz + pendingChunkZ); ++ final byte stage = this.chunkTicketStage.get(neighbour); ++ if (stage != CHUNK_TICKET_STAGE_GENERATED && stage != CHUNK_TICKET_STAGE_TICK) { ++ break tick_check_outer; ++ } ++ } ++ } ++ // only gets here if all neighbours were marked as generated or ticking themselves ++ this.tickingQueue.dequeueLong(); ++ this.pushDelayedTicketOp( ++ ChunkHolderManager.TicketOperation.addAndRemove( ++ pendingTicking, ++ REGION_PLAYER_TICKET, TICK_TICKET_LEVEL, this.idBoxed, ++ REGION_PLAYER_TICKET, GENERATED_TICKET_LEVEL, this.idBoxed ++ ) ++ ); ++ // there is no queue to add after ticking ++ final byte prev = this.chunkTicketStage.put(pendingTicking, CHUNK_TICKET_STAGE_TICK); ++ if (prev != CHUNK_TICKET_STAGE_GENERATED) { ++ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_GENERATED + ", not " + prev); ++ } ++ } ++ ++ // try to pull sending chunks ++ final long maxSends = Math.max(0L, Math.min(MAX_RATE, Integer.MAX_VALUE)); // no logic to track concurrent sends ++ final int maxSendsThisTick = Math.min((int)this.chunkSendLimiter.takeAllocation(time, sendRate, maxSends), this.sendQueue.size()); ++ // we do not return sends that we took from the allocation back because we want to limit the max send rate, not target it ++ for (int i = 0; i < maxSendsThisTick; ++i) { ++ final long pendingSend = this.sendQueue.firstLong(); ++ final int pendingSendX = CoordinateUtils.getChunkX(pendingSend); ++ final int pendingSendZ = CoordinateUtils.getChunkZ(pendingSend); ++ final LevelChunk chunk = this.world.chunkSource.getChunkAtIfLoadedMainThreadNoCache(pendingSendX, pendingSendZ); ++ if (!chunk.areNeighboursLoaded(1) || !TickThread.isTickThreadFor(this.world, pendingSendX, pendingSendZ)) { ++ // nothing to do ++ // the target chunk may not be owned by this region, but this should be resolved in the future ++ break; ++ } ++ this.sendQueue.dequeueLong(); ++ ++ this.sendChunk(pendingSendX, pendingSendZ); ++ if (this.removed) { ++ // sendChunk may invoke plugin logic ++ return; ++ } ++ } ++ ++ this.flushDelayedTicketOps(); ++ // we assume propagate ticket levels happens after this call ++ } ++ ++ void add() { ++ TickThread.ensureTickThread(this.player, "Cannot add player asynchronously"); ++ if (this.removed) { ++ throw new IllegalStateException("Adding removed player chunk loader"); ++ } ++ final ViewDistances playerDistances = this.player.getViewDistances(); ++ final ViewDistances worldDistances = this.world.getViewDistances(); ++ final int chunkX = this.player.chunkPosition().x; ++ final int chunkZ = this.player.chunkPosition().z; ++ ++ final int tickViewDistance = getTickDistance(playerDistances.tickViewDistance, worldDistances.tickViewDistance); ++ // load view cannot be less-than tick view + 1 ++ final int loadViewDistance = getLoadViewDistance(tickViewDistance, playerDistances.loadViewDistance, worldDistances.loadViewDistance); ++ // send view cannot be greater-than load view ++ final int clientViewDistance = getClientViewDistance(this.player); ++ final int sendViewDistance = getSendViewDistance(loadViewDistance, clientViewDistance, playerDistances.sendViewDistance, worldDistances.sendViewDistance); ++ ++ // send view distances ++ this.player.connection.send(this.updateClientChunkRadius(sendViewDistance)); ++ this.player.connection.send(this.updateClientSimulationDistance(tickViewDistance)); ++ ++ // add to distance maps ++ this.broadcastMap.add(chunkX, chunkZ, sendViewDistance); ++ this.loadTicketCleanup.add(chunkX, chunkZ, loadViewDistance + 1); ++ this.tickMap.add(chunkX, chunkZ, tickViewDistance); ++ ++ // update chunk center ++ this.player.connection.send(this.updateClientChunkCenter(chunkX, chunkZ)); ++ ++ // now we can update ++ this.update(); ++ } ++ ++ private boolean isLoadedChunkGeneratable(final int chunkX, final int chunkZ) { ++ return this.isLoadedChunkGeneratable(this.world.chunkSource.getChunkAtImmediately(chunkX, chunkZ)); ++ } ++ ++ private boolean isLoadedChunkGeneratable(final ChunkAccess chunkAccess) { ++ final BelowZeroRetrogen belowZeroRetrogen; ++ return chunkAccess != null && ( ++ chunkAccess.getStatus() == ChunkStatus.FULL || ++ ((belowZeroRetrogen = chunkAccess.getBelowZeroRetrogen()) != null && belowZeroRetrogen.targetStatus().isOrAfter(ChunkStatus.FULL)) ++ ); ++ } ++ ++ void update() { ++ TickThread.ensureTickThread(this.player, "Cannot update player asynchronously"); ++ if (this.removed) { ++ throw new IllegalStateException("Updating removed player chunk loader"); ++ } ++ final ViewDistances playerDistances = this.player.getViewDistances(); ++ final ViewDistances worldDistances = this.world.getViewDistances(); ++ ++ final int tickViewDistance = getTickDistance(playerDistances.tickViewDistance, worldDistances.tickViewDistance); ++ // load view cannot be less-than tick view + 1 ++ final int loadViewDistance = getLoadViewDistance(tickViewDistance, playerDistances.loadViewDistance, worldDistances.loadViewDistance); ++ // send view cannot be greater-than load view ++ final int clientViewDistance = getClientViewDistance(this.player); ++ final int sendViewDistance = getSendViewDistance(loadViewDistance, clientViewDistance, playerDistances.sendViewDistance, worldDistances.sendViewDistance); ++ ++ final ChunkPos playerPos = this.player.chunkPosition(); ++ final boolean canGenerateChunks = this.canPlayerGenerateChunks(); ++ final int currentChunkX = playerPos.x; ++ final int currentChunkZ = playerPos.z; ++ ++ final int prevChunkX = this.lastChunkX; ++ final int prevChunkZ = this.lastChunkZ; ++ ++ if ( ++ // has view distance stayed the same? ++ sendViewDistance == this.lastSendDistance ++ && loadViewDistance == this.lastLoadDistance ++ && tickViewDistance == this.lastTickDistance ++ ++ // has our chunk stayed the same? ++ && prevChunkX == currentChunkX ++ && prevChunkZ == currentChunkZ ++ ++ // can we still generate chunks? ++ && this.canGenerateChunks == canGenerateChunks ++ ) { ++ // nothing we care about changed, so we're not re-calculating ++ return; ++ } ++ ++ // update distance maps ++ this.broadcastMap.update(currentChunkX, currentChunkZ, sendViewDistance); ++ this.loadTicketCleanup.update(currentChunkX, currentChunkZ, loadViewDistance + 1); ++ this.tickMap.update(currentChunkX, currentChunkZ, tickViewDistance); ++ if (sendViewDistance > loadViewDistance || tickViewDistance > loadViewDistance) { ++ throw new IllegalStateException(); ++ } ++ ++ // update VDs for client ++ // this should be after the distance map updates, as they will send unload packets ++ if (this.lastSentChunkRadius != sendViewDistance) { ++ this.player.connection.send(this.updateClientChunkRadius(sendViewDistance)); ++ } ++ if (this.lastSentSimulationDistance != tickViewDistance) { ++ this.player.connection.send(this.updateClientSimulationDistance(tickViewDistance)); ++ } ++ ++ this.sendQueue.clear(); ++ this.tickingQueue.clear(); ++ this.generatingQueue.clear(); ++ this.genQueue.clear(); ++ this.loadingQueue.clear(); ++ this.loadQueue.clear(); ++ ++ this.lastChunkX = currentChunkX; ++ this.lastChunkZ = currentChunkZ; ++ this.lastSendDistance = sendViewDistance; ++ this.lastLoadDistance = loadViewDistance; ++ this.lastTickDistance = tickViewDistance; ++ this.canGenerateChunks = canGenerateChunks; ++ ++ // +1 since we need to load chunks +1 around the load view distance... ++ final long[] toIterate = SEARCH_RADIUS_ITERATION_LIST[loadViewDistance + 1]; ++ // the iteration order is by increasing manhattan distance - so, we do NOT need to ++ // sort anything in the queue! ++ for (final long deltaChunk : toIterate) { ++ final int dx = CoordinateUtils.getChunkX(deltaChunk); ++ final int dz = CoordinateUtils.getChunkZ(deltaChunk); ++ final int chunkX = dx + currentChunkX; ++ final int chunkZ = dz + currentChunkZ; ++ final long chunk = CoordinateUtils.getChunkKey(chunkX, chunkZ); ++ final int squareDistance = Math.max(Math.abs(dx), Math.abs(dz)); ++ final int manhattanDistance = Math.abs(dx) + Math.abs(dz); ++ ++ // since chunk sending is not by radius alone, we need an extra check here to account for ++ // everything <= sendDistance ++ // Note: Vanilla may want to send chunks outside the send view distance, so we do need ++ // the dist <= view check ++ final boolean sendChunk = squareDistance <= sendViewDistance ++ && wantChunkLoaded(currentChunkX, currentChunkZ, chunkX, chunkZ, sendViewDistance); ++ final boolean sentChunk = sendChunk ? this.sentChunks.contains(chunk) : this.sentChunks.remove(chunk); ++ ++ if (!sendChunk && sentChunk) { ++ // have sent the chunk, but don't want it anymore ++ // unload it now ++ this.sendUnloadChunkRaw(chunkX, chunkZ); ++ } ++ ++ final byte stage = this.chunkTicketStage.get(chunk); ++ switch (stage) { ++ case CHUNK_TICKET_STAGE_NONE: { ++ // we want the chunk to be at least loaded ++ this.loadQueue.enqueue(chunk); ++ break; ++ } ++ case CHUNK_TICKET_STAGE_LOADING: { ++ this.loadingQueue.enqueue(chunk); ++ break; ++ } ++ case CHUNK_TICKET_STAGE_LOADED: { ++ if (canGenerateChunks || this.isLoadedChunkGeneratable(chunkX, chunkZ)) { ++ this.genQueue.enqueue(chunk); ++ } ++ break; ++ } ++ case CHUNK_TICKET_STAGE_GENERATING: { ++ this.generatingQueue.enqueue(chunk); ++ break; ++ } ++ case CHUNK_TICKET_STAGE_GENERATED: { ++ if (sendChunk && !sentChunk) { ++ this.sendQueue.enqueue(chunk); ++ } ++ if (squareDistance <= tickViewDistance) { ++ this.tickingQueue.enqueue(chunk); ++ } ++ break; ++ } ++ case CHUNK_TICKET_STAGE_TICK: { ++ if (sendChunk && !sentChunk) { ++ this.sendQueue.enqueue(chunk); ++ } ++ break; ++ } ++ default: { ++ throw new IllegalStateException("Unknown stage: " + stage); ++ } ++ } ++ } ++ ++ // update the chunk center ++ // this must be done last so that the client does not ignore any of our unload chunk packets above ++ if (this.lastSentChunkCenterX != currentChunkX || this.lastSentChunkCenterZ != currentChunkZ) { ++ this.player.connection.send(this.updateClientChunkCenter(currentChunkX, currentChunkZ)); ++ } ++ ++ this.flushDelayedTicketOps(); ++ } ++ ++ void remove() { ++ TickThread.ensureTickThread(this.player, "Cannot add player asynchronously"); ++ if (this.removed) { ++ throw new IllegalStateException("Removing removed player chunk loader"); ++ } ++ this.removed = true; ++ // sends the chunk unload packets ++ this.broadcastMap.remove(); ++ // cleans up loading/generating tickets ++ this.loadTicketCleanup.remove(); ++ // cleans up ticking tickets ++ this.tickMap.remove(); ++ ++ // purge queues ++ this.sendQueue.clear(); ++ this.tickingQueue.clear(); ++ this.generatingQueue.clear(); ++ this.genQueue.clear(); ++ this.loadingQueue.clear(); ++ this.loadQueue.clear(); ++ ++ // flush ticket changes ++ this.flushDelayedTicketOps(); ++ ++ // now all tickets should be removed, which is all of our external state ++ } ++ } ++ ++ // TODO rebase into util patch ++ private static final class AllocatingRateLimiter { ++ ++ // max difference granularity in ns ++ private static final long MAX_GRANULARITY = TimeUnit.SECONDS.toNanos(1L); ++ ++ private double allocation; ++ private long lastAllocationUpdate; ++ private double takeCarry; ++ private long lastTakeUpdate; ++ ++ // rate in units/s, and time in ns ++ public void tickAllocation(final long time, final double rate, final double maxAllocation) { ++ final long diff = Math.min(MAX_GRANULARITY, time - this.lastAllocationUpdate); ++ this.lastAllocationUpdate = time; ++ ++ this.allocation = Math.min(maxAllocation - this.takeCarry, this.allocation + rate * (diff*1.0E-9D)); ++ } ++ ++ // rate in units/s, and time in ns ++ public long takeAllocation(final long time, final double rate, final long maxTake) { ++ if (maxTake < 1L) { ++ return 0L; ++ } ++ ++ double ret = this.takeCarry; ++ final long diff = Math.min(MAX_GRANULARITY, time - this.lastTakeUpdate); ++ this.lastTakeUpdate = time; ++ ++ // note: abs(takeCarry) <= 1.0 ++ final double take = Math.min(Math.min((double)maxTake - this.takeCarry, this.allocation), rate * (diff*1.0E-9)); ++ ++ ret += take; ++ this.allocation -= take; ++ ++ final long retInteger = (long)Math.floor(ret); ++ this.takeCarry = ret - (double)retInteger; ++ ++ return retInteger; ++ } ++ } ++ ++ public static abstract class SingleUserAreaMap { ++ ++ private static final int NOT_SET = Integer.MIN_VALUE; ++ ++ private final T parameter; ++ private int lastChunkX = NOT_SET; ++ private int lastChunkZ = NOT_SET; ++ private int distance = NOT_SET; ++ ++ public SingleUserAreaMap(final T parameter) { ++ this.parameter = parameter; ++ } ++ ++ /* math sign function except 0 returns 1 */ ++ protected static int sign(int val) { ++ return 1 | (val >> (Integer.SIZE - 1)); ++ } ++ ++ protected abstract void addCallback(final T parameter, final int chunkX, final int chunkZ); ++ ++ protected abstract void removeCallback(final T parameter, final int chunkX, final int chunkZ); ++ ++ private void addToNew(final T parameter, final int chunkX, final int chunkZ, final int distance) { ++ final int maxX = chunkX + distance; ++ final int maxZ = chunkZ + distance; ++ ++ for (int cx = chunkX - distance; cx <= maxX; ++cx) { ++ for (int cz = chunkZ - distance; cz <= maxZ; ++cz) { ++ this.addCallback(parameter, cx, cz); ++ } ++ } ++ } ++ ++ private void removeFromOld(final T parameter, final int chunkX, final int chunkZ, final int distance) { ++ final int maxX = chunkX + distance; ++ final int maxZ = chunkZ + distance; ++ ++ for (int cx = chunkX - distance; cx <= maxX; ++cx) { ++ for (int cz = chunkZ - distance; cz <= maxZ; ++cz) { ++ this.removeCallback(parameter, cx, cz); ++ } ++ } ++ } ++ ++ public final boolean add(final int chunkX, final int chunkZ, final int distance) { ++ if (distance < 0) { ++ throw new IllegalArgumentException(Integer.toString(distance)); ++ } ++ if (this.lastChunkX != NOT_SET) { ++ return false; ++ } ++ this.lastChunkX = chunkX; ++ this.lastChunkZ = chunkZ; ++ this.distance = distance; ++ ++ this.addToNew(this.parameter, chunkX, chunkZ, distance); ++ ++ return true; ++ } ++ ++ public final boolean update(final int toX, final int toZ, final int newViewDistance) { ++ if (newViewDistance < 0) { ++ throw new IllegalArgumentException(Integer.toString(newViewDistance)); ++ } ++ final int fromX = this.lastChunkX; ++ final int fromZ = this.lastChunkZ; ++ final int oldViewDistance = this.distance; ++ if (fromX == NOT_SET) { ++ return false; ++ } ++ ++ this.lastChunkX = toX; ++ this.lastChunkZ = toZ; ++ ++ final T parameter = this.parameter; ++ ++ ++ final int dx = toX - fromX; ++ final int dz = toZ - fromZ; ++ ++ final int totalX = IntegerUtil.branchlessAbs(fromX - toX); ++ final int totalZ = IntegerUtil.branchlessAbs(fromZ - toZ); ++ ++ if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) { ++ // teleported? ++ this.removeFromOld(parameter, fromX, fromZ, oldViewDistance); ++ this.addToNew(parameter, toX, toZ, newViewDistance); ++ return true; ++ } ++ ++ if (oldViewDistance != newViewDistance) { ++ // remove loop ++ ++ final int oldMinX = fromX - oldViewDistance; ++ final int oldMinZ = fromZ - oldViewDistance; ++ final int oldMaxX = fromX + oldViewDistance; ++ final int oldMaxZ = fromZ + oldViewDistance; ++ for (int currX = oldMinX; currX <= oldMaxX; ++currX) { ++ for (int currZ = oldMinZ; currZ <= oldMaxZ; ++currZ) { ++ ++ // only remove if we're outside the new view distance... ++ if (Math.max(IntegerUtil.branchlessAbs(currX - toX), IntegerUtil.branchlessAbs(currZ - toZ)) > newViewDistance) { ++ this.removeCallback(parameter, currX, currZ); ++ } ++ } ++ } ++ ++ // add loop ++ ++ final int newMinX = toX - newViewDistance; ++ final int newMinZ = toZ - newViewDistance; ++ final int newMaxX = toX + newViewDistance; ++ final int newMaxZ = toZ + newViewDistance; ++ for (int currX = newMinX; currX <= newMaxX; ++currX) { ++ for (int currZ = newMinZ; currZ <= newMaxZ; ++currZ) { ++ ++ // only add if we're outside the old view distance... ++ if (Math.max(IntegerUtil.branchlessAbs(currX - fromX), IntegerUtil.branchlessAbs(currZ - fromZ)) > oldViewDistance) { ++ this.addCallback(parameter, currX, currZ); ++ } ++ } ++ } ++ ++ return true; ++ } ++ ++ // x axis is width ++ // z axis is height ++ // right refers to the x axis of where we moved ++ // top refers to the z axis of where we moved ++ ++ // same view distance ++ ++ // used for relative positioning ++ final int up = sign(dz); // 1 if dz >= 0, -1 otherwise ++ final int right = sign(dx); // 1 if dx >= 0, -1 otherwise ++ ++ // The area excluded by overlapping the two view distance squares creates four rectangles: ++ // Two on the left, and two on the right. The ones on the left we consider the "removed" section ++ // and on the right the "added" section. ++ // https://i.imgur.com/MrnOBgI.png is a reference image. Note that the outside border is not actually ++ // exclusive to the regions they surround. ++ ++ // 4 points of the rectangle ++ int maxX; // exclusive ++ int minX; // inclusive ++ int maxZ; // exclusive ++ int minZ; // inclusive ++ ++ if (dx != 0) { ++ // handle right addition ++ ++ maxX = toX + (oldViewDistance * right) + right; // exclusive ++ minX = fromX + (oldViewDistance * right) + right; // inclusive ++ maxZ = fromZ + (oldViewDistance * up) + up; // exclusive ++ minZ = toZ - (oldViewDistance * up); // inclusive ++ ++ for (int currX = minX; currX != maxX; currX += right) { ++ for (int currZ = minZ; currZ != maxZ; currZ += up) { ++ this.addCallback(parameter, currX, currZ); ++ } ++ } ++ } ++ ++ if (dz != 0) { ++ // handle up addition ++ ++ maxX = toX + (oldViewDistance * right) + right; // exclusive ++ minX = toX - (oldViewDistance * right); // inclusive ++ maxZ = toZ + (oldViewDistance * up) + up; // exclusive ++ minZ = fromZ + (oldViewDistance * up) + up; // inclusive ++ ++ for (int currX = minX; currX != maxX; currX += right) { ++ for (int currZ = minZ; currZ != maxZ; currZ += up) { ++ this.addCallback(parameter, currX, currZ); ++ } ++ } ++ } ++ ++ if (dx != 0) { ++ // handle left removal ++ ++ maxX = toX - (oldViewDistance * right); // exclusive ++ minX = fromX - (oldViewDistance * right); // inclusive ++ maxZ = fromZ + (oldViewDistance * up) + up; // exclusive ++ minZ = toZ - (oldViewDistance * up); // inclusive ++ ++ for (int currX = minX; currX != maxX; currX += right) { ++ for (int currZ = minZ; currZ != maxZ; currZ += up) { ++ this.removeCallback(parameter, currX, currZ); ++ } ++ } ++ } ++ ++ if (dz != 0) { ++ // handle down removal ++ ++ maxX = fromX + (oldViewDistance * right) + right; // exclusive ++ minX = fromX - (oldViewDistance * right); // inclusive ++ maxZ = toZ - (oldViewDistance * up); // exclusive ++ minZ = fromZ - (oldViewDistance * up); // inclusive ++ ++ for (int currX = minX; currX != maxX; currX += right) { ++ for (int currZ = minZ; currZ != maxZ; currZ += up) { ++ this.removeCallback(parameter, currX, currZ); ++ } ++ } ++ } ++ ++ return true; ++ } ++ ++ public final boolean remove() { ++ final int chunkX = this.lastChunkX; ++ final int chunkZ = this.lastChunkZ; ++ final int distance = this.distance; ++ if (chunkX == NOT_SET) { ++ return false; ++ } ++ ++ this.lastChunkX = this.lastChunkZ = this.distance = NOT_SET; ++ ++ this.removeFromOld(this.parameter, chunkX, chunkZ, distance); ++ ++ return true; ++ } ++ } ++ ++ static final class CountedSRSWLinkedQueue { ++ ++ private final SRSWLinkedQueue queue = new SRSWLinkedQueue<>(); ++ private volatile long countAdded; ++ private volatile long countRemoved; ++ ++ private static final VarHandle COUNT_ADDED_HANDLE = ConcurrentUtil.getVarHandle(CountedSRSWLinkedQueue.class, "countAdded", long.class); ++ private static final VarHandle COUNT_REMOVED_HANDLE = ConcurrentUtil.getVarHandle(CountedSRSWLinkedQueue.class, "countRemoved", long.class); ++ ++ private long getCountAddedPlain() { ++ return (long)COUNT_ADDED_HANDLE.get(this); ++ } ++ ++ private long getCountAddedAcquire() { ++ return (long)COUNT_ADDED_HANDLE.getAcquire(this); ++ } ++ ++ private void setCountAddedRelease(final long to) { ++ COUNT_ADDED_HANDLE.setRelease(this, to); ++ } ++ ++ private long getCountRemovedPlain() { ++ return (long)COUNT_REMOVED_HANDLE.get(this); ++ } ++ ++ private long getCountRemovedAcquire() { ++ return (long)COUNT_REMOVED_HANDLE.getAcquire(this); ++ } ++ ++ private void setCountRemovedRelease(final long to) { ++ COUNT_REMOVED_HANDLE.setRelease(this, to); ++ } ++ ++ public void add(final E element) { ++ this.setCountAddedRelease(this.getCountAddedPlain() + 1L); ++ this.queue.addLast(element); ++ } ++ ++ public E poll() { ++ final E ret = this.queue.poll(); ++ if (ret != null) { ++ this.setCountRemovedRelease(this.getCountRemovedPlain() + 1L); ++ } ++ ++ return ret; ++ } ++ ++ public long size() { ++ final long removed = this.getCountRemovedAcquire(); ++ final long added = this.getCountAddedAcquire(); ++ ++ return added - removed; ++ } ++ } ++} diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java new file mode 100644 index 0000000000000000000000000000000000000000..61c170555c8854b102c640b0b6a615f9f732edbf @@ -3520,10 +5001,10 @@ index 0000000000000000000000000000000000000000..61c170555c8854b102c640b0b6a615f9 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java new file mode 100644 -index 0000000000000000000000000000000000000000..a08cde4eefe879adcee7c4118bc38f98c5097ed0 +index 0000000000000000000000000000000000000000..8a11e10b01fa012b2f98b1c193c53251e848f909 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java -@@ -0,0 +1,1328 @@ +@@ -0,0 +1,1338 @@ +package io.papermc.paper.chunk.system.io; + +import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue; @@ -4345,8 +5826,14 @@ index 0000000000000000000000000000000000000000..a08cde4eefe879adcee7c4118bc38f98 + return file.hasChunk(chunkPos) ? Boolean.TRUE : Boolean.FALSE; + }); + } else { ++ // first check if the region file for sure does not exist ++ if (taskController.doesRegionFileNotExist(chunkX, chunkZ)) { ++ return Boolean.FALSE; ++ } // else: it either exists or is not known, fall back to checking the loaded region file ++ + return taskController.computeForRegionFileIfLoaded(chunkX, chunkZ, (final RegionFile file) -> { + if (file == null) { // null if not loaded ++ // not sure at this point, let the I/O thread figure it out + return Boolean.TRUE; + } + @@ -4642,6 +6129,10 @@ index 0000000000000000000000000000000000000000..a08cde4eefe879adcee7c4118bc38f98 + return !this.tasks.isEmpty(); + } + ++ public boolean doesRegionFileNotExist(final int chunkX, final int chunkZ) { ++ return this.getCache().doesRegionFileNotExistNoIO(new ChunkPos(chunkX, chunkZ)); ++ } ++ + public T computeForRegionFile(final int chunkX, final int chunkZ, final boolean existingOnly, final Function function) { + final RegionFileStorage cache = this.getCache(); + final RegionFile regionFile; @@ -4854,17 +6345,16 @@ index 0000000000000000000000000000000000000000..a08cde4eefe879adcee7c4118bc38f98 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java b/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java new file mode 100644 -index 0000000000000000000000000000000000000000..0b7a2b0ead4f3bc07bfd9a38c2b7cf024bd140c6 +index 0000000000000000000000000000000000000000..36e93fefdfbebddce4c153974c7cd81af3cb92e9 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java -@@ -0,0 +1,280 @@ +@@ -0,0 +1,283 @@ +package io.papermc.paper.chunk.system.light; + +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; +import ca.spottedleaf.starlight.common.light.BlockStarLightEngine; +import ca.spottedleaf.starlight.common.light.SkyStarLightEngine; +import ca.spottedleaf.starlight.common.light.StarLightInterface; -+import io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler; +import io.papermc.paper.util.CoordinateUtils; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.shorts.ShortCollection; @@ -4873,6 +6363,7 @@ index 0000000000000000000000000000000000000000..0b7a2b0ead4f3bc07bfd9a38c2b7cf02 +import net.minecraft.core.SectionPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.chunk.ChunkStatus; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; @@ -5061,7 +6552,10 @@ index 0000000000000000000000000000000000000000..0b7a2b0ead4f3bc07bfd9a38c2b7cf02 + this.chunkCoordinate = chunkCoordinate; + this.lightEngine = lightEngine; + this.queue = queue; -+ this.task = queue.world.chunkTaskScheduler.lightExecutor.createTask(this, priority); ++ this.task = queue.world.chunkTaskScheduler.radiusAwareScheduler.createTask( ++ CoordinateUtils.getChunkX(chunkCoordinate), CoordinateUtils.getChunkZ(chunkCoordinate), ++ ChunkStatus.LIGHT.writeRadius, this, priority ++ ); + } + + public void schedule() { @@ -5090,23 +6584,23 @@ index 0000000000000000000000000000000000000000..0b7a2b0ead4f3bc07bfd9a38c2b7cf02 + + @Override + public void run() { ++ synchronized (this.queue) { ++ this.queue.chunkTasks.remove(this.chunkCoordinate); ++ } ++ ++ boolean litChunk = false; ++ if (this.lightTasks != null) { ++ for (final BooleanSupplier run : this.lightTasks) { ++ if (run.getAsBoolean()) { ++ litChunk = true; ++ break; ++ } ++ } ++ } ++ + final SkyStarLightEngine skyEngine = this.lightEngine.getSkyLightEngine(); + final BlockStarLightEngine blockEngine = this.lightEngine.getBlockLightEngine(); + try { -+ synchronized (this.queue) { -+ this.queue.chunkTasks.remove(this.chunkCoordinate); -+ } -+ -+ boolean litChunk = false; -+ if (this.lightTasks != null) { -+ for (final BooleanSupplier run : this.lightTasks) { -+ if (run.getAsBoolean()) { -+ litChunk = true; -+ break; -+ } -+ } -+ } -+ + final long coordinate = this.chunkCoordinate; + final int chunkX = CoordinateUtils.getChunkX(coordinate); + final int chunkZ = CoordinateUtils.getChunkZ(coordinate); @@ -5359,14 +6853,16 @@ index 0000000000000000000000000000000000000000..d72041aa814ff179e6e29a45dcd359a9 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java new file mode 100644 -index 0000000000000000000000000000000000000000..fb42d776f15f735fb59e972e00e2b512c23a8387 +index 0000000000000000000000000000000000000000..300700477ee34bc22b31315825c0e40f61070cd5 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java -@@ -0,0 +1,121 @@ +@@ -0,0 +1,135 @@ +package io.papermc.paper.chunk.system.scheduling; + +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; +import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; ++import com.mojang.logging.LogUtils; ++import io.papermc.paper.chunk.system.poi.PoiChunk; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.chunk.ChunkAccess; @@ -5374,10 +6870,13 @@ index 0000000000000000000000000000000000000000..fb42d776f15f735fb59e972e00e2b512 +import net.minecraft.world.level.chunk.ImposterProtoChunk; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; ++import org.slf4j.Logger; +import java.lang.invoke.VarHandle; + +public final class ChunkFullTask extends ChunkProgressionTask implements Runnable { + ++ private static final Logger LOGGER = LogUtils.getClassLogger(); ++ + protected final NewChunkHolder chunkHolder; + protected final ChunkAccess fromChunk; + protected final PrioritisedExecutor.PrioritisedTask convertToFullTask; @@ -5400,6 +6899,15 @@ index 0000000000000000000000000000000000000000..fb42d776f15f735fb59e972e00e2b512 + // See Vanilla protoChunkToFullChunk for what this function should be doing + final LevelChunk chunk; + try { ++ // moved from the load from nbt stage into here ++ final PoiChunk poiChunk = this.chunkHolder.getPoiChunk(); ++ if (poiChunk == null) { ++ LOGGER.error("Expected poi chunk to be loaded with chunk for task " + this.toString()); ++ } else { ++ poiChunk.load(); ++ this.world.getPoiManager().checkConsistency(this.fromChunk); ++ } ++ + if (this.fromChunk instanceof ImposterProtoChunk wrappedFull) { + chunk = wrappedFull.getWrapped(); + } else { @@ -5486,12 +6994,13 @@ index 0000000000000000000000000000000000000000..fb42d776f15f735fb59e972e00e2b512 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java new file mode 100644 -index 0000000000000000000000000000000000000000..748cc48c6c42c694d1c9b685e96fbe6d8337d3f3 +index 0000000000000000000000000000000000000000..718c1dd7b52fb9a501d552fdbcb3f9ff79d127d8 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -@@ -0,0 +1,1211 @@ +@@ -0,0 +1,1371 @@ +package io.papermc.paper.chunk.system.scheduling; + ++import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue; +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; +import ca.spottedleaf.concurrentutil.map.SWMRLong2ObjectHashTable; +import co.aikar.timings.Timing; @@ -5992,6 +7501,21 @@ index 0000000000000000000000000000000000000000..748cc48c6c42c694d1c9b685e96fbe6d + } + } + ++ // atomic with respect to all add/remove/addandremove ticket calls for the given chunk ++ public boolean addIfRemovedTicket(final long chunk, final TicketType addType, final int addLevel, final T addIdentifier, ++ final TicketType removeType, final int removeLevel, final V removeIdentifier) { ++ this.ticketLock.lock(); ++ try { ++ if (this.removeTicketAtLevel(removeType, chunk, removeLevel, removeIdentifier)) { ++ this.addTicketAtLevel(addType, chunk, addLevel, addIdentifier); ++ return true; ++ } ++ return false; ++ } finally { ++ this.ticketLock.unlock(); ++ } ++ } ++ + public void removeAllTicketsFor(final TicketType ticketType, final int ticketLevel, final T ticketIdentifier) { + if (ticketLevel > MAX_TICKET_LEVEL) { + return; @@ -6399,6 +7923,148 @@ index 0000000000000000000000000000000000000000..748cc48c6c42c694d1c9b685e96fbe6d + } + } + ++ public enum TicketOperationType { ++ ADD, REMOVE, ADD_IF_REMOVED, ADD_AND_REMOVE ++ } ++ ++ public static record TicketOperation ( ++ TicketOperationType op, long chunkCoord, ++ TicketType ticketType, int ticketLevel, T identifier, ++ TicketType ticketType2, int ticketLevel2, V identifier2 ++ ) { ++ ++ private TicketOperation(TicketOperationType op, long chunkCoord, ++ TicketType ticketType, int ticketLevel, T identifier) { ++ this(op, chunkCoord, ticketType, ticketLevel, identifier, null, 0, null); ++ } ++ ++ public static TicketOperation addOp(final ChunkPos chunk, final TicketType type, final int ticketLevel, final T identifier) { ++ return addOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier); ++ } ++ ++ public static TicketOperation addOp(final int chunkX, final int chunkZ, final TicketType type, final int ticketLevel, final T identifier) { ++ return addOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier); ++ } ++ ++ public static TicketOperation addOp(final long chunk, final TicketType type, final int ticketLevel, final T identifier) { ++ return new TicketOperation<>(TicketOperationType.ADD, chunk, type, ticketLevel, identifier); ++ } ++ ++ public static TicketOperation removeOp(final ChunkPos chunk, final TicketType type, final int ticketLevel, final T identifier) { ++ return removeOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier); ++ } ++ ++ public static TicketOperation removeOp(final int chunkX, final int chunkZ, final TicketType type, final int ticketLevel, final T identifier) { ++ return removeOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier); ++ } ++ ++ public static TicketOperation removeOp(final long chunk, final TicketType type, final int ticketLevel, final T identifier) { ++ return new TicketOperation<>(TicketOperationType.REMOVE, chunk, type, ticketLevel, identifier); ++ } ++ ++ public static TicketOperation addIfRemovedOp(final long chunk, ++ final TicketType addType, final int addLevel, final T addIdentifier, ++ final TicketType removeType, final int removeLevel, final V removeIdentifier) { ++ return new TicketOperation<>( ++ TicketOperationType.ADD_IF_REMOVED, chunk, addType, addLevel, addIdentifier, ++ removeType, removeLevel, removeIdentifier ++ ); ++ } ++ ++ public static TicketOperation addAndRemove(final long chunk, ++ final TicketType addType, final int addLevel, final T addIdentifier, ++ final TicketType removeType, final int removeLevel, final V removeIdentifier) { ++ return new TicketOperation<>( ++ TicketOperationType.ADD_AND_REMOVE, chunk, addType, addLevel, addIdentifier, ++ removeType, removeLevel, removeIdentifier ++ ); ++ } ++ } ++ ++ private final MultiThreadedQueue> delayedTicketUpdates = new MultiThreadedQueue<>(); ++ ++ // note: MUST hold ticket lock, otherwise operation ordering is lost ++ private boolean drainTicketUpdates() { ++ boolean ret = false; ++ ++ TicketOperation operation; ++ while ((operation = this.delayedTicketUpdates.poll()) != null) { ++ switch (operation.op) { ++ case ADD: { ++ ret |= this.addTicketAtLevel(operation.ticketType, operation.chunkCoord, operation.ticketLevel, operation.identifier); ++ break; ++ } ++ case REMOVE: { ++ ret |= this.removeTicketAtLevel(operation.ticketType, operation.chunkCoord, operation.ticketLevel, operation.identifier); ++ break; ++ } ++ case ADD_IF_REMOVED: { ++ ret |= this.addIfRemovedTicket( ++ operation.chunkCoord, ++ operation.ticketType, operation.ticketLevel, operation.identifier, ++ operation.ticketType2, operation.ticketLevel2, operation.identifier2 ++ ); ++ break; ++ } ++ case ADD_AND_REMOVE: { ++ ret = true; ++ this.addAndRemoveTickets( ++ operation.chunkCoord, ++ operation.ticketType, operation.ticketLevel, operation.identifier, ++ operation.ticketType2, operation.ticketLevel2, operation.identifier2 ++ ); ++ break; ++ } ++ } ++ } ++ ++ return ret; ++ } ++ ++ public Boolean tryDrainTicketUpdates() { ++ boolean ret = false; ++ for (;;) { ++ final boolean acquired = this.ticketLock.tryLock(); ++ try { ++ if (!acquired) { ++ return ret ? Boolean.TRUE : null; ++ } ++ ++ ret |= this.drainTicketUpdates(); ++ } finally { ++ if (acquired) { ++ this.ticketLock.unlock(); ++ } ++ } ++ if (this.delayedTicketUpdates.isEmpty()) { ++ return Boolean.valueOf(ret); ++ } // else: try to re-acquire ++ } ++ } ++ ++ public void pushDelayedTicketUpdate(final TicketOperation operation) { ++ this.delayedTicketUpdates.add(operation); ++ } ++ ++ public void pushDelayedTicketUpdates(final Collection> operations) { ++ this.delayedTicketUpdates.addAll(operations); ++ } ++ ++ public Boolean tryProcessTicketUpdates() { ++ final boolean acquired = this.ticketLock.tryLock(); ++ try { ++ if (!acquired) { ++ return null; ++ } ++ ++ return Boolean.valueOf(this.processTicketUpdates(false, true, null)); ++ } finally { ++ if (acquired) { ++ this.ticketLock.unlock(); ++ } ++ } ++ } ++ + private final ThreadLocal BLOCK_TICKET_UPDATES = ThreadLocal.withInitial(() -> { + return Boolean.FALSE; + }); @@ -6445,6 +8111,8 @@ index 0000000000000000000000000000000000000000..748cc48c6c42c694d1c9b685e96fbe6d + + this.ticketLock.lock(); + try { ++ this.drainTicketUpdates(); ++ + final boolean levelsUpdated = this.ticketLevelPropagator.propagateUpdates(); + if (levelsUpdated) { + // Unlike CB, ticket level updates cannot happen recursively. Thank god. @@ -6890,10 +8558,10 @@ index 0000000000000000000000000000000000000000..53ddd7e9ac05e6a9eb809f329796e6d4 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java new file mode 100644 -index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335355b69d6 +index 0000000000000000000000000000000000000000..34dc2153e90a29bc9102d9497c3c53b5de15508e --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java -@@ -0,0 +1,499 @@ +@@ -0,0 +1,483 @@ +package io.papermc.paper.chunk.system.scheduling; + +import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue; @@ -6930,9 +8598,11 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + private final NewChunkHolder chunkHolder; + private final ChunkDataLoadTask loadTask; + -+ private boolean cancelled; ++ private volatile boolean cancelled; + private NewChunkHolder.GenericDataLoadTaskCallback entityLoadTask; + private NewChunkHolder.GenericDataLoadTaskCallback poiLoadTask; ++ private GenericDataLoadTask.TaskResult loadResult; ++ private final AtomicInteger taskCountToComplete = new AtomicInteger(3); // one for poi, one for entity, and one for chunk data + + protected ChunkLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX, final int chunkZ, + final NewChunkHolder chunkHolder, final PrioritisedExecutor.Priority priority) { @@ -6940,10 +8610,18 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + this.chunkHolder = chunkHolder; + this.loadTask = new ChunkDataLoadTask(scheduler, world, chunkX, chunkZ, priority); + this.loadTask.addCallback((final GenericDataLoadTask.TaskResult result) -> { -+ ChunkLoadTask.this.complete(result == null ? null : result.left(), result == null ? null : result.right()); ++ ChunkLoadTask.this.loadResult = result; // must be before getAndDecrement ++ ChunkLoadTask.this.tryCompleteLoad(); + }); + } + ++ private void tryCompleteLoad() { ++ if (this.taskCountToComplete.decrementAndGet() == 0) { ++ final GenericDataLoadTask.TaskResult result = this.cancelled ? null : this.loadResult; // only after the getAndDecrement ++ ChunkLoadTask.this.complete(result == null ? null : result.left(), result == null ? null : result.right()); ++ } ++ } ++ + @Override + public ChunkStatus getTargetStatus() { + return ChunkStatus.EMPTY; @@ -6961,11 +8639,8 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + final NewChunkHolder.GenericDataLoadTaskCallback entityLoadTask; + final NewChunkHolder.GenericDataLoadTaskCallback poiLoadTask; + -+ final AtomicInteger count = new AtomicInteger(); + final Consumer> scheduleLoadTask = (final GenericDataLoadTask.TaskResult result) -> { -+ if (count.decrementAndGet() == 0) { -+ ChunkLoadTask.this.loadTask.schedule(false); -+ } ++ ChunkLoadTask.this.tryCompleteLoad(); + }; + + // NOTE: it is IMPOSSIBLE for getOrLoadEntityData/getOrLoadPoiData to complete synchronously, because @@ -6981,16 +8656,16 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + } + if (!this.chunkHolder.isEntityChunkNBTLoaded()) { + entityLoadTask = this.chunkHolder.getOrLoadEntityData((Consumer)scheduleLoadTask); -+ count.setPlain(count.getPlain() + 1); + } else { + entityLoadTask = null; ++ this.taskCountToComplete.getAndDecrement(); // we know the chunk load is not done here, as it is not scheduled + } + + if (!this.chunkHolder.isPoiChunkLoaded()) { + poiLoadTask = this.chunkHolder.getOrLoadPoiData((Consumer)scheduleLoadTask); -+ count.setPlain(count.getPlain() + 1); + } else { + poiLoadTask = null; ++ this.taskCountToComplete.getAndDecrement(); // we know the chunk load is not done here, as it is not scheduled + } + + this.entityLoadTask = entityLoadTask; @@ -7003,21 +8678,22 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + entityLoadTask.schedule(); + } + -+ if (poiLoadTask != null) { ++ if (poiLoadTask != null) { + poiLoadTask.schedule(); + } + -+ if (entityLoadTask == null && poiLoadTask == null) { -+ // no need to wait on those, we can schedule now -+ this.loadTask.schedule(false); -+ } ++ this.loadTask.schedule(false); + } + + @Override + public void cancel() { + // must be before load task access, so we can synchronise with the writes to the fields ++ final boolean scheduled; + this.scheduler.schedulingLock.lock(); + try { ++ // fix cancellation of chunk load task - must read field here, as it may be written later conucrrently - ++ // we need to know if we scheduled _before_ cancellation ++ scheduled = this.scheduled; + this.cancelled = true; + } finally { + this.scheduler.schedulingLock.unlock(); @@ -7025,15 +8701,31 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + + /* + Note: The entityLoadTask/poiLoadTask do not complete when cancelled, -+ but this is fine because if they are successfully cancelled then -+ we will successfully cancel the load task, which will complete when cancelled ++ so we need to manually try to complete in those cases ++ It is also important to note that we set the cancelled field first, just in case ++ the chunk load task attempts to complete with a non-null value + */ + -+ if (this.entityLoadTask != null) { -+ this.entityLoadTask.cancel(); -+ } -+ if (this.poiLoadTask != null) { -+ this.poiLoadTask.cancel(); ++ if (scheduled) { ++ // since we scheduled, we need to cancel the tasks ++ if (this.entityLoadTask != null) { ++ if (this.entityLoadTask.cancel()) { ++ this.tryCompleteLoad(); ++ } ++ } ++ if (this.poiLoadTask != null) { ++ if (this.poiLoadTask.cancel()) { ++ this.tryCompleteLoad(); ++ } ++ } ++ } else { ++ // since nothing was scheduled, we need to decrement the task count here ourselves ++ ++ // for entity load task ++ this.tryCompleteLoad(); ++ ++ // for poi load task ++ this.tryCompleteLoad(); + } + this.loadTask.cancel(); + } @@ -7145,7 +8837,7 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + } + } + -+ public final class ChunkDataLoadTask extends CallbackDataLoadTask { ++ public static final class ChunkDataLoadTask extends CallbackDataLoadTask { + protected ChunkDataLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX, + final int chunkZ, final PrioritisedExecutor.Priority priority) { + super(scheduler, world, chunkX, chunkZ, RegionFileIOThread.RegionFileType.CHUNK_DATA, priority); @@ -7158,7 +8850,7 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + + @Override + protected boolean hasOnMain() { -+ return true; ++ return false; + } + + @Override @@ -7168,35 +8860,30 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + + @Override + protected PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final PrioritisedExecutor.Priority priority) { -+ return this.scheduler.createChunkTask(this.chunkX, this.chunkZ, run, priority); ++ throw new UnsupportedOperationException(); + } + + @Override -+ protected TaskResult completeOnMainOffMain(final ChunkSerializer.InProgressChunkHolder data, final Throwable throwable) { -+ if (data != null) { -+ return null; -+ } ++ protected TaskResult completeOnMainOffMain(final ChunkAccess data, final Throwable throwable) { ++ throw new UnsupportedOperationException(); ++ } + -+ final PoiChunk poiChunk = ChunkLoadTask.this.chunkHolder.getPoiChunk(); -+ if (poiChunk == null) { -+ LOGGER.error("Expected poi chunk to be loaded with chunk for task " + this.toString()); -+ } else if (!poiChunk.isLoaded()) { -+ // need to call poiChunk.load() on main -+ return null; -+ } -+ -+ return new TaskResult<>(this.getEmptyChunk(), null); ++ private ProtoChunk getEmptyChunk() { ++ return new ProtoChunk( ++ new ChunkPos(this.chunkX, this.chunkZ), UpgradeData.EMPTY, this.world, ++ this.world.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData)null ++ ); + } + + @Override -+ protected TaskResult runOffMain(final CompoundTag data, final Throwable throwable) { ++ protected TaskResult runOffMain(final CompoundTag data, final Throwable throwable) { + if (throwable != null) { + LOGGER.error("Failed to load chunk data for task: " + this.toString() + ", chunk data will be lost", throwable); -+ return new TaskResult<>(null, null); ++ return new TaskResult<>(this.getEmptyChunk(), null); + } + + if (data == null) { -+ return new TaskResult<>(null, null); ++ return new TaskResult<>(this.getEmptyChunk(), null); + } + + // need to convert data, and then deserialize it @@ -7215,53 +8902,18 @@ index 0000000000000000000000000000000000000000..be6f3f6a57668a9bd50d0ea5f2dd2335 + this.world, chunkMap.getPoiManager(), chunkPos, converted, true + ); + -+ return new TaskResult<>(chunkHolder, null); ++ return new TaskResult<>(chunkHolder.protoChunk, null); + } catch (final ThreadDeath death) { + throw death; + } catch (final Throwable thr2) { + LOGGER.error("Failed to parse chunk data for task: " + this.toString() + ", chunk data will be lost", thr2); -+ return new TaskResult<>(null, thr2); ++ return new TaskResult<>(this.getEmptyChunk(), null); + } + } + -+ private ProtoChunk getEmptyChunk() { -+ return new ProtoChunk( -+ new ChunkPos(this.chunkX, this.chunkZ), UpgradeData.EMPTY, this.world, -+ this.world.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData)null -+ ); -+ } -+ + @Override -+ protected TaskResult runOnMain(final ChunkSerializer.InProgressChunkHolder data, final Throwable throwable) { -+ final PoiChunk poiChunk = ChunkLoadTask.this.chunkHolder.getPoiChunk(); -+ if (poiChunk == null) { -+ LOGGER.error("Expected poi chunk to be loaded with chunk for task " + this.toString()); -+ } else { -+ poiChunk.load(); -+ } -+ -+ if (data == null || data.protoChunk == null) { -+ // throwable could be non-null, but the off-main task will print its exceptions - so we don't need to care, -+ // it's handled already -+ -+ return new TaskResult<>(this.getEmptyChunk(), null); -+ } -+ -+ // have tasks to run (at this point, it's just the POI consistency checking) -+ try { -+ if (data.tasks != null) { -+ for (int i = 0, len = data.tasks.size(); i < len; ++i) { -+ data.tasks.poll().run(); -+ } -+ } -+ -+ return new TaskResult<>(data.protoChunk, null); -+ } catch (final ThreadDeath death) { -+ throw death; -+ } catch (final Throwable thr2) { -+ LOGGER.error("Failed to parse main tasks for task " + this.toString() + ", chunk data will be lost", thr2); -+ return new TaskResult<>(this.getEmptyChunk(), null); -+ } ++ protected TaskResult runOnMain(final ChunkAccess data, final Throwable throwable) { ++ throw new UnsupportedOperationException(); + } + } + @@ -7506,17 +9158,17 @@ index 0000000000000000000000000000000000000000..322675a470eacbf0e5452f4009c643f2 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java new file mode 100644 -index 0000000000000000000000000000000000000000..84d6af5c28cd0e81d50701bebe122f462720fbf8 +index 0000000000000000000000000000000000000000..d2bb266a5ed344507058778a94a8a4dcac61ba17 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java -@@ -0,0 +1,775 @@ +@@ -0,0 +1,770 @@ +package io.papermc.paper.chunk.system.scheduling; + +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedThreadPool; -+import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedThreadedTaskQueue; +import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; +import com.mojang.logging.LogUtils; ++import io.papermc.paper.chunk.system.scheduling.queue.RadiusAwarePrioritisedExecutor; +import io.papermc.paper.configuration.GlobalConfiguration; +import io.papermc.paper.util.CoordinateUtils; +import io.papermc.paper.util.TickThread; @@ -7533,7 +9185,6 @@ index 0000000000000000000000000000000000000000..84d6af5c28cd0e81d50701bebe122f46 +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; -+import org.bukkit.Bukkit; +import org.slf4j.Logger; +import java.io.File; +import java.util.ArrayDeque; @@ -7546,7 +9197,6 @@ index 0000000000000000000000000000000000000000..84d6af5c28cd0e81d50701bebe122f46 +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; -+import java.util.function.BooleanSupplier; +import java.util.function.Consumer; + +public final class ChunkTaskScheduler { @@ -7620,9 +9270,9 @@ index 0000000000000000000000000000000000000000..84d6af5c28cd0e81d50701bebe122f46 + + public final ServerLevel world; + public final PrioritisedThreadPool workers; -+ public final PrioritisedThreadPool.PrioritisedPoolExecutor lightExecutor; -+ public final PrioritisedThreadPool.PrioritisedPoolExecutor genExecutor; ++ public final RadiusAwarePrioritisedExecutor radiusAwareScheduler; + public final PrioritisedThreadPool.PrioritisedPoolExecutor parallelGenExecutor; ++ private final PrioritisedThreadPool.PrioritisedPoolExecutor radiusAwareGenExecutor; + public final PrioritisedThreadPool.PrioritisedPoolExecutor loadExecutor; + + private final PrioritisedThreadedTaskQueue mainThreadExecutor = new PrioritisedThreadedTaskQueue(); @@ -7703,12 +9353,11 @@ index 0000000000000000000000000000000000000000..84d6af5c28cd0e81d50701bebe122f46 + this.workers = workers; + + final String worldName = world.getWorld().getName(); -+ this.genExecutor = workers.createExecutor("Chunk single-threaded generation executor for world '" + worldName + "'", 1); -+ // same as genExecutor, as there are race conditions between updating blocks in FEATURE status while lighting chunks -+ this.lightExecutor = this.genExecutor; -+ this.parallelGenExecutor = newChunkSystemGenParallelism <= 1 ? this.genExecutor -+ : workers.createExecutor("Chunk parallel generation executor for world '" + worldName + "'", newChunkSystemGenParallelism); ++ this.parallelGenExecutor = workers.createExecutor("Chunk parallel generation executor for world '" + worldName + "'", Math.max(1, newChunkSystemGenParallelism)); ++ this.radiusAwareGenExecutor = ++ newChunkSystemGenParallelism <= 1 ? this.parallelGenExecutor : workers.createExecutor("Chunk radius aware generator for world '" + worldName + "'", newChunkSystemGenParallelism); + this.loadExecutor = workers.createExecutor("Chunk load executor for world '" + worldName + "'", newChunkSystemLoadParallelism); ++ this.radiusAwareScheduler = new RadiusAwarePrioritisedExecutor(this.radiusAwareGenExecutor, Math.max(1, newChunkSystemGenParallelism)); + this.chunkHolderManager = new ChunkHolderManager(world, this); + } + @@ -8200,16 +9849,14 @@ index 0000000000000000000000000000000000000000..84d6af5c28cd0e81d50701bebe122f46 + } + + public boolean halt(final boolean sync, final long maxWaitNS) { -+ this.lightExecutor.halt(); -+ this.genExecutor.halt(); ++ this.radiusAwareGenExecutor.halt(); + this.parallelGenExecutor.halt(); + this.loadExecutor.halt(); + final long time = System.nanoTime(); + if (sync) { + for (long failures = 9L;; failures = ConcurrentUtil.linearLongBackoff(failures, 500_000L, 50_000_000L)) { + if ( -+ !this.lightExecutor.isActive() && -+ !this.genExecutor.isActive() && ++ !this.radiusAwareGenExecutor.isActive() && + !this.parallelGenExecutor.isActive() && + !this.loadExecutor.isActive() + ) { @@ -8287,10 +9934,10 @@ index 0000000000000000000000000000000000000000..84d6af5c28cd0e81d50701bebe122f46 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java new file mode 100644 -index 0000000000000000000000000000000000000000..73ce0909bd89244835a0d0f2030a25871461f1e0 +index 0000000000000000000000000000000000000000..ecc366a4176b2efadc46aa91aa21621f0fc6abe9 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java -@@ -0,0 +1,209 @@ +@@ -0,0 +1,212 @@ +package io.papermc.paper.chunk.system.scheduling; + +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; @@ -8332,8 +9979,11 @@ index 0000000000000000000000000000000000000000..73ce0909bd89244835a0d0f2030a2587 + this.fromStatus = chunk.getStatus(); + this.toStatus = toStatus; + this.neighbours = neighbours; -+ this.generateTask = (this.toStatus.isParallelCapable ? this.scheduler.parallelGenExecutor : this.scheduler.genExecutor) -+ .createTask(this, priority); ++ if (this.toStatus.isParallelCapable) { ++ this.generateTask = this.scheduler.parallelGenExecutor.createTask(this, priority); ++ } else { ++ this.generateTask = this.scheduler.radiusAwareScheduler.createTask(chunkX, chunkZ, this.toStatus.writeRadius, this, priority); ++ } + } + + @Override @@ -9254,10 +10904,10 @@ index 0000000000000000000000000000000000000000..396d72c00e47cf1669ae20dc839c1c96 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java new file mode 100644 -index 0000000000000000000000000000000000000000..8013dd333e27aa5fd0beb431fa32491eec9f5246 +index 0000000000000000000000000000000000000000..efc9b7a304f10b6a23a36cffb0a4aaea6ab71129 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -@@ -0,0 +1,2077 @@ +@@ -0,0 +1,2099 @@ +package io.papermc.paper.chunk.system.scheduling; + +import ca.spottedleaf.concurrentutil.completable.Completable; @@ -9416,6 +11066,12 @@ index 0000000000000000000000000000000000000000..8013dd333e27aa5fd0beb431fa32491e + LOGGER.error("Unhandled entity data load exception, data data will be lost: ", result.right()); + } + ++ // Folia start - mark these tasks as completed before releasing the scheduling lock ++ for (final GenericDataLoadTaskCallback callback : waiters) { ++ callback.markCompleted(); ++ } ++ // Folia end - mark these tasks as completed before releasing the scheduling lock ++ + completeWaiters = waiters; + } else { + // cancelled @@ -9447,7 +11103,7 @@ index 0000000000000000000000000000000000000000..8013dd333e27aa5fd0beb431fa32491e + // avoid holding the scheduling lock while completing + if (completeWaiters != null) { + for (final GenericDataLoadTaskCallback callback : completeWaiters) { -+ callback.accept(result); ++ callback.acceptCompleted(result); // Folia - mark these tasks as completed before releasing the scheduling lock + } + } + @@ -9533,6 +11189,12 @@ index 0000000000000000000000000000000000000000..8013dd333e27aa5fd0beb431fa32491e + LOGGER.error("Unhandled poi load exception, poi data will be lost: ", result.right()); + } + ++ // Folia start - mark these tasks as completed before releasing the scheduling lock ++ for (final GenericDataLoadTaskCallback callback : waiters) { ++ callback.markCompleted(); ++ } ++ // Folia end - mark these tasks as completed before releasing the scheduling lock ++ + completeWaiters = waiters; + } else { + // cancelled @@ -9564,7 +11226,7 @@ index 0000000000000000000000000000000000000000..8013dd333e27aa5fd0beb431fa32491e + // avoid holding the scheduling lock while completing + if (completeWaiters != null) { + for (final GenericDataLoadTaskCallback callback : completeWaiters) { -+ callback.accept(result); ++ callback.acceptCompleted(result); // Folia - mark these tasks as completed before releasing the scheduling lock + } + } + this.scheduler.schedulingLock.lock(); @@ -9617,7 +11279,7 @@ index 0000000000000000000000000000000000000000..8013dd333e27aa5fd0beb431fa32491e + } + } + -+ public static abstract class GenericDataLoadTaskCallback implements Cancellable, Consumer> { ++ public static abstract class GenericDataLoadTaskCallback implements Cancellable { // Folia - mark callbacks as completed before unlocking scheduling lock + + protected final Consumer> consumer; + protected final NewChunkHolder chunkHolder; @@ -9653,13 +11315,23 @@ index 0000000000000000000000000000000000000000..8013dd333e27aa5fd0beb431fa32491e + return this.completed = true; + } + -+ @Override -+ public void accept(final GenericDataLoadTask.TaskResult result) { ++ // Folia start - mark callbacks as completed before unlocking scheduling lock ++ // must hold scheduling lock ++ void markCompleted() { ++ if (this.completed) { ++ throw new IllegalStateException("May not be completed here"); ++ } ++ this.completed = true; ++ } ++ // Folia end - mark callbacks as completed before unlocking scheduling lock ++ ++ // Folia - mark callbacks as completed before unlocking scheduling lock ++ void acceptCompleted(final GenericDataLoadTask.TaskResult result) { + if (result != null) { -+ if (this.setCompleted()) { ++ if (this.completed) { // Folia - mark callbacks as completed before unlocking scheduling lock + this.consumer.accept(result); + } else { -+ throw new IllegalStateException("Cannot be cancelled at this point"); ++ throw new IllegalStateException("Cannot be uncompleted at this point"); // Folia - mark callbacks as completed before unlocking scheduling lock + } + } else { + throw new NullPointerException("Result cannot be null (cancelled)"); @@ -11556,6 +13228,680 @@ index 0000000000000000000000000000000000000000..b4c56bf12dc8dd17452210ece4fd6741 + + protected abstract void raisePriorityScheduled(final PrioritisedExecutor.Priority priority); +} +diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/queue/RadiusAwarePrioritisedExecutor.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/queue/RadiusAwarePrioritisedExecutor.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3272f73013ea7d4efdd0ae2903925cc543be7075 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/queue/RadiusAwarePrioritisedExecutor.java +@@ -0,0 +1,668 @@ ++package io.papermc.paper.chunk.system.scheduling.queue; ++ ++import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; ++import io.papermc.paper.util.CoordinateUtils; ++import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; ++import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; ++import java.util.ArrayList; ++import java.util.Comparator; ++import java.util.List; ++import java.util.PriorityQueue; ++ ++public class RadiusAwarePrioritisedExecutor { ++ ++ private static final Comparator DEPENDENCY_NODE_COMPARATOR = (final DependencyNode t1, final DependencyNode t2) -> { ++ return Long.compare(t1.id, t2.id); ++ }; ++ ++ private final DependencyTree[] queues = new DependencyTree[PrioritisedExecutor.Priority.TOTAL_SCHEDULABLE_PRIORITIES]; ++ private static final int NO_TASKS_QUEUED = -1; ++ private int selectedQueue = NO_TASKS_QUEUED; ++ private boolean canQueueTasks = true; ++ ++ public RadiusAwarePrioritisedExecutor(final PrioritisedExecutor executor, final int maxToSchedule) { ++ for (int i = 0; i < this.queues.length; ++i) { ++ this.queues[i] = new DependencyTree(this, executor, maxToSchedule, i); ++ } ++ } ++ ++ private boolean canQueueTasks() { ++ return this.canQueueTasks; ++ } ++ ++ private List treeFinished() { ++ this.canQueueTasks = true; ++ for (int priority = 0; priority < this.queues.length; ++priority) { ++ final DependencyTree queue = this.queues[priority]; ++ if (queue.hasWaitingTasks()) { ++ final List ret = queue.tryPushTasks(); ++ ++ if (ret == null || ret.isEmpty()) { ++ // this happens when the tasks in the wait queue were purged ++ // in this case, the queue was actually empty, we just had to purge it ++ // if we set the selected queue without scheduling any tasks, the queue will never be unselected ++ // as that requires a scheduled task completing... ++ continue; ++ } ++ ++ this.selectedQueue = priority; ++ return ret; ++ } ++ } ++ ++ this.selectedQueue = NO_TASKS_QUEUED; ++ ++ return null; ++ } ++ ++ private List queue(final Task task, final PrioritisedExecutor.Priority priority) { ++ final int priorityId = priority.priority; ++ final DependencyTree queue = this.queues[priorityId]; ++ ++ final DependencyNode node = new DependencyNode(task, queue); ++ ++ if (task.dependencyNode != null) { ++ throw new IllegalStateException(); ++ } ++ task.dependencyNode = node; ++ ++ queue.pushNode(node); ++ ++ if (this.selectedQueue == NO_TASKS_QUEUED) { ++ this.canQueueTasks = true; ++ this.selectedQueue = priorityId; ++ return queue.tryPushTasks(); ++ } ++ ++ if (!this.canQueueTasks) { ++ return null; ++ } ++ ++ if (PrioritisedExecutor.Priority.isHigherPriority(priorityId, this.selectedQueue)) { ++ // prevent the lower priority tree from queueing more tasks ++ this.canQueueTasks = false; ++ return null; ++ } ++ ++ // priorityId != selectedQueue: lower priority, don't care - treeFinished will pick it up ++ return priorityId == this.selectedQueue ? queue.tryPushTasks() : null; ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius, ++ final Runnable run, final PrioritisedExecutor.Priority priority) { ++ if (radius < 0) { ++ throw new IllegalArgumentException("Radius must be > 0: " + radius); ++ } ++ return new Task(this, chunkX, chunkZ, radius, run, priority); ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius, ++ final Runnable run) { ++ return this.createTask(chunkX, chunkZ, radius, run, PrioritisedExecutor.Priority.NORMAL); ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius, ++ final Runnable run, final PrioritisedExecutor.Priority priority) { ++ final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run, priority); ++ ++ ret.queue(); ++ ++ return ret; ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius, ++ final Runnable run) { ++ final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run); ++ ++ ret.queue(); ++ ++ return ret; ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run, final PrioritisedExecutor.Priority priority) { ++ return new Task(this, 0, 0, -1, run, priority); ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run) { ++ return this.createInfiniteRadiusTask(run, PrioritisedExecutor.Priority.NORMAL); ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run, final PrioritisedExecutor.Priority priority) { ++ final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, priority); ++ ++ ret.queue(); ++ ++ return ret; ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run) { ++ final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, PrioritisedExecutor.Priority.NORMAL); ++ ++ ret.queue(); ++ ++ return ret; ++ } ++ ++ // all accesses must be synchronised by the radius aware object ++ private static final class DependencyTree { ++ ++ private final RadiusAwarePrioritisedExecutor scheduler; ++ private final PrioritisedExecutor executor; ++ private final int maxToSchedule; ++ private final int treeIndex; ++ ++ private int currentlyExecuting; ++ private long idGenerator; ++ ++ private final PriorityQueue awaiting = new PriorityQueue<>(DEPENDENCY_NODE_COMPARATOR); ++ ++ private final PriorityQueue infiniteRadius = new PriorityQueue<>(DEPENDENCY_NODE_COMPARATOR); ++ private boolean isInfiniteRadiusScheduled; ++ ++ private final Long2ReferenceOpenHashMap nodeByPosition = new Long2ReferenceOpenHashMap<>(); ++ ++ public DependencyTree(final RadiusAwarePrioritisedExecutor scheduler, final PrioritisedExecutor executor, ++ final int maxToSchedule, final int treeIndex) { ++ this.scheduler = scheduler; ++ this.executor = executor; ++ this.maxToSchedule = maxToSchedule; ++ this.treeIndex = treeIndex; ++ } ++ ++ public boolean hasWaitingTasks() { ++ return !this.awaiting.isEmpty() || !this.infiniteRadius.isEmpty(); ++ } ++ ++ private long nextId() { ++ return this.idGenerator++; ++ } ++ ++ private boolean isExecutingAnyTasks() { ++ return this.currentlyExecuting != 0; ++ } ++ ++ private void pushNode(final DependencyNode node) { ++ if (!node.task.isFiniteRadius()) { ++ this.infiniteRadius.add(node); ++ return; ++ } ++ ++ // set up dependency for node ++ final Task task = node.task; ++ ++ final int centerX = task.chunkX; ++ final int centerZ = task.chunkZ; ++ final int radius = task.radius; ++ ++ final int minX = centerX - radius; ++ final int maxX = centerX + radius; ++ ++ final int minZ = centerZ - radius; ++ final int maxZ = centerZ + radius; ++ ++ ReferenceOpenHashSet parents = null; ++ for (int currZ = minZ; currZ <= maxZ; ++currZ) { ++ for (int currX = minX; currX <= maxX; ++currX) { ++ final DependencyNode dependency = this.nodeByPosition.put(CoordinateUtils.getChunkKey(currX, currZ), node); ++ if (dependency != null) { ++ if (parents == null) { ++ parents = new ReferenceOpenHashSet<>(); ++ } ++ if (parents.add(dependency)) { ++ // added a dependency, so we need to add as a child to the dependency ++ if (dependency.children == null) { ++ dependency.children = new ArrayList<>(); ++ } ++ dependency.children.add(node); ++ } ++ } ++ } ++ } ++ ++ if (parents == null) { ++ // no dependencies, add straight to awaiting ++ this.awaiting.add(node); ++ } else { ++ node.parents = parents; ++ // we will be added to awaiting once we have no parents ++ } ++ } ++ ++ // called only when a node is returned after being executed ++ private List returnNode(final DependencyNode node) { ++ final Task task = node.task; ++ ++ // now that the task is completed, we can push its children to the awaiting queue ++ this.pushChildren(node); ++ ++ if (task.isFiniteRadius()) { ++ // remove from dependency map ++ this.removeNodeFromMap(node); ++ } else { ++ // mark as no longer executing infinite radius ++ if (!this.isInfiniteRadiusScheduled) { ++ throw new IllegalStateException(); ++ } ++ this.isInfiniteRadiusScheduled = false; ++ } ++ ++ // decrement executing count, we are done executing this task ++ --this.currentlyExecuting; ++ ++ if (this.currentlyExecuting == 0) { ++ return this.scheduler.treeFinished(); ++ } ++ ++ return this.scheduler.canQueueTasks() ? this.tryPushTasks() : null; ++ } ++ ++ private List tryPushTasks() { ++ // tasks are not queued, but only created here - we do hold the lock for the map ++ List ret = null; ++ PrioritisedExecutor.PrioritisedTask pushedTask; ++ while ((pushedTask = this.tryPushTask()) != null) { ++ if (ret == null) { ++ ret = new ArrayList<>(); ++ } ++ ret.add(pushedTask); ++ } ++ ++ return ret; ++ } ++ ++ private void removeNodeFromMap(final DependencyNode node) { ++ final Task task = node.task; ++ ++ final int centerX = task.chunkX; ++ final int centerZ = task.chunkZ; ++ final int radius = task.radius; ++ ++ final int minX = centerX - radius; ++ final int maxX = centerX + radius; ++ ++ final int minZ = centerZ - radius; ++ final int maxZ = centerZ + radius; ++ ++ for (int currZ = minZ; currZ <= maxZ; ++currZ) { ++ for (int currX = minX; currX <= maxX; ++currX) { ++ this.nodeByPosition.remove(CoordinateUtils.getChunkKey(currX, currZ), node); ++ } ++ } ++ } ++ ++ private void pushChildren(final DependencyNode node) { ++ // add all the children that we can into awaiting ++ final List children = node.children; ++ if (children != null) { ++ for (int i = 0, len = children.size(); i < len; ++i) { ++ final DependencyNode child = children.get(i); ++ if (!child.parents.remove(node)) { ++ throw new IllegalStateException(); ++ } ++ if (child.parents.isEmpty()) { ++ // no more dependents, we can push to awaiting ++ child.parents = null; ++ // even if the child is purged, we need to push it so that its children will be pushed ++ this.awaiting.add(child); ++ } ++ } ++ } ++ } ++ ++ private DependencyNode pollAwaiting() { ++ final DependencyNode ret = this.awaiting.poll(); ++ if (ret == null) { ++ return ret; ++ } ++ ++ if (ret.parents != null) { ++ throw new IllegalStateException(); ++ } ++ ++ if (ret.purged) { ++ // need to manually remove from state here ++ this.pushChildren(ret); ++ this.removeNodeFromMap(ret); ++ } // else: delay children push until the task has finished ++ ++ return ret; ++ } ++ ++ private DependencyNode pollInfinite() { ++ return this.infiniteRadius.poll(); ++ } ++ ++ public PrioritisedExecutor.PrioritisedTask tryPushTask() { ++ if (this.currentlyExecuting >= this.maxToSchedule || this.isInfiniteRadiusScheduled) { ++ return null; ++ } ++ ++ DependencyNode firstInfinite; ++ while ((firstInfinite = this.infiniteRadius.peek()) != null && firstInfinite.purged) { ++ this.pollInfinite(); ++ } ++ ++ DependencyNode firstAwaiting; ++ while ((firstAwaiting = this.awaiting.peek()) != null && firstAwaiting.purged) { ++ this.pollAwaiting(); ++ } ++ ++ if (firstInfinite == null && firstAwaiting == null) { ++ return null; ++ } ++ ++ // firstAwaiting compared to firstInfinite ++ final int compare; ++ ++ if (firstAwaiting == null) { ++ // we choose first infinite, or infinite < awaiting ++ compare = 1; ++ } else if (firstInfinite == null) { ++ // we choose first awaiting, or awaiting < infinite ++ compare = -1; ++ } else { ++ compare = DEPENDENCY_NODE_COMPARATOR.compare(firstAwaiting, firstInfinite); ++ } ++ ++ if (compare >= 0) { ++ if (this.currentlyExecuting != 0) { ++ // don't queue infinite task while other tasks are executing in parallel ++ return null; ++ } ++ ++this.currentlyExecuting; ++ this.pollInfinite(); ++ this.isInfiniteRadiusScheduled = true; ++ return firstInfinite.task.pushTask(this.executor); ++ } else { ++ ++this.currentlyExecuting; ++ this.pollAwaiting(); ++ return firstAwaiting.task.pushTask(this.executor); ++ } ++ } ++ } ++ ++ private static final class DependencyNode { ++ ++ private final Task task; ++ private final DependencyTree tree; ++ ++ // dependency tree fields ++ // (must hold lock on the scheduler to use) ++ // null is the same as empty, we just use it so that we don't allocate the set unless we need to ++ private List children; ++ // null is the same as empty, indicating that this task is considered "awaiting" ++ private ReferenceOpenHashSet parents; ++ // false -> scheduled and not cancelled ++ // true -> scheduled but cancelled ++ private boolean purged; ++ private final long id; ++ ++ public DependencyNode(final Task task, final DependencyTree tree) { ++ this.task = task; ++ this.id = tree.nextId(); ++ this.tree = tree; ++ } ++ } ++ ++ private static final class Task implements PrioritisedExecutor.PrioritisedTask, Runnable { ++ ++ // task specific fields ++ private final RadiusAwarePrioritisedExecutor scheduler; ++ private final int chunkX; ++ private final int chunkZ; ++ private final int radius; ++ private Runnable run; ++ private PrioritisedExecutor.Priority priority; ++ ++ private DependencyNode dependencyNode; ++ private PrioritisedExecutor.PrioritisedTask queuedTask; ++ ++ private Task(final RadiusAwarePrioritisedExecutor scheduler, final int chunkX, final int chunkZ, final int radius, ++ final Runnable run, final PrioritisedExecutor.Priority priority) { ++ this.scheduler = scheduler; ++ this.chunkX = chunkX; ++ this.chunkZ = chunkZ; ++ this.radius = radius; ++ this.run = run; ++ this.priority = priority; ++ } ++ ++ private boolean isFiniteRadius() { ++ return this.radius >= 0; ++ } ++ ++ private PrioritisedExecutor.PrioritisedTask pushTask(final PrioritisedExecutor executor) { ++ return this.queuedTask = executor.createTask(this, this.priority); ++ } ++ ++ private void executeTask() { ++ final Runnable run = this.run; ++ this.run = null; ++ run.run(); ++ } ++ ++ private static void scheduleTasks(final List toSchedule) { ++ if (toSchedule != null) { ++ for (int i = 0, len = toSchedule.size(); i < len; ++i) { ++ toSchedule.get(i).queue(); ++ } ++ } ++ } ++ ++ private void returnNode() { ++ final List toSchedule; ++ synchronized (this.scheduler) { ++ final DependencyNode node = this.dependencyNode; ++ this.dependencyNode = null; ++ toSchedule = node.tree.returnNode(node); ++ } ++ ++ scheduleTasks(toSchedule); ++ } ++ ++ @Override ++ public void run() { ++ final Runnable run = this.run; ++ this.run = null; ++ try { ++ run.run(); ++ } finally { ++ this.returnNode(); ++ } ++ } ++ ++ @Override ++ public boolean queue() { ++ final List toSchedule; ++ synchronized (this.scheduler) { ++ if (this.queuedTask != null || this.dependencyNode != null || this.priority == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ toSchedule = this.scheduler.queue(this, this.priority); ++ } ++ ++ scheduleTasks(toSchedule); ++ return true; ++ } ++ ++ @Override ++ public boolean cancel() { ++ final PrioritisedExecutor.PrioritisedTask task; ++ synchronized (this.scheduler) { ++ if ((task = this.queuedTask) == null) { ++ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ this.priority = PrioritisedExecutor.Priority.COMPLETING; ++ if (this.dependencyNode != null) { ++ this.dependencyNode.purged = true; ++ this.dependencyNode = null; ++ } ++ ++ return true; ++ } ++ } ++ ++ if (task.cancel()) { ++ // must manually return the node ++ this.run = null; ++ this.returnNode(); ++ return true; ++ } ++ return false; ++ } ++ ++ @Override ++ public boolean execute() { ++ final PrioritisedExecutor.PrioritisedTask task; ++ synchronized (this.scheduler) { ++ if ((task = this.queuedTask) == null) { ++ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ this.priority = PrioritisedExecutor.Priority.COMPLETING; ++ if (this.dependencyNode != null) { ++ this.dependencyNode.purged = true; ++ this.dependencyNode = null; ++ } ++ // fall through to execution logic ++ } ++ } ++ ++ if (task != null) { ++ // will run the return node logic automatically ++ return task.execute(); ++ } else { ++ // don't run node removal/insertion logic, we aren't actually removed from the dependency tree ++ this.executeTask(); ++ return true; ++ } ++ } ++ ++ @Override ++ public PrioritisedExecutor.Priority getPriority() { ++ final PrioritisedExecutor.PrioritisedTask task; ++ synchronized (this.scheduler) { ++ if ((task = this.queuedTask) == null) { ++ return this.priority; ++ } ++ } ++ ++ return task.getPriority(); ++ } ++ ++ @Override ++ public boolean setPriority(final PrioritisedExecutor.Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ final PrioritisedExecutor.PrioritisedTask task; ++ List toSchedule = null; ++ synchronized (this.scheduler) { ++ if ((task = this.queuedTask) == null) { ++ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ if (this.priority == priority) { ++ return true; ++ } ++ ++ this.priority = priority; ++ if (this.dependencyNode != null) { ++ // need to re-insert node ++ this.dependencyNode.purged = true; ++ this.dependencyNode = null; ++ toSchedule = this.scheduler.queue(this, priority); ++ } ++ } ++ } ++ ++ if (task != null) { ++ return task.setPriority(priority); ++ } ++ ++ scheduleTasks(toSchedule); ++ ++ return true; ++ } ++ ++ @Override ++ public boolean raisePriority(final PrioritisedExecutor.Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ final PrioritisedExecutor.PrioritisedTask task; ++ List toSchedule = null; ++ synchronized (this.scheduler) { ++ if ((task = this.queuedTask) == null) { ++ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ if (this.priority.isHigherOrEqualPriority(priority)) { ++ return true; ++ } ++ ++ this.priority = priority; ++ if (this.dependencyNode != null) { ++ // need to re-insert node ++ this.dependencyNode.purged = true; ++ this.dependencyNode = null; ++ toSchedule = this.scheduler.queue(this, priority); ++ } ++ } ++ } ++ ++ if (task != null) { ++ return task.raisePriority(priority); ++ } ++ ++ scheduleTasks(toSchedule); ++ ++ return true; ++ } ++ ++ @Override ++ public boolean lowerPriority(final PrioritisedExecutor.Priority priority) { ++ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { ++ throw new IllegalArgumentException("Invalid priority " + priority); ++ } ++ ++ final PrioritisedExecutor.PrioritisedTask task; ++ List toSchedule = null; ++ synchronized (this.scheduler) { ++ if ((task = this.queuedTask) == null) { ++ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { ++ return false; ++ } ++ ++ if (this.priority.isLowerOrEqualPriority(priority)) { ++ return true; ++ } ++ ++ this.priority = priority; ++ if (this.dependencyNode != null) { ++ // need to re-insert node ++ this.dependencyNode.purged = true; ++ this.dependencyNode = null; ++ toSchedule = this.scheduler.queue(this, priority); ++ } ++ } ++ } ++ ++ if (task != null) { ++ return task.lowerPriority(priority); ++ } ++ ++ scheduleTasks(toSchedule); ++ ++ 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 a52e6e8be323863ece6624a8ae7f9455279bdc23..e3467aaf6d0c8d486b84362e3c20b3fe631b50ff 100644 --- a/src/main/java/io/papermc/paper/command/PaperCommand.java @@ -11838,8 +14184,131 @@ index 0000000000000000000000000000000000000000..a6fb7ae77d7cad2243e28a33718e4631 + } + +} +diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +index 52b02cb1f02d1c65b840f38cfc8baee500aa2259..09234062090c210227350cafeed141f8cb73108a 100644 +--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java ++++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +@@ -274,4 +274,43 @@ public class GlobalConfiguration extends ConfigurationPart { + public boolean useDimensionTypeForCustomSpawners = false; + public boolean strictAdvancementDimensionCheck = false; + } ++ ++ public ChunkLoadingBasic chunkLoadingBasic; ++ ++ public class ChunkLoadingBasic extends ConfigurationPart { ++ @Comment("The maximum rate in chunks per second that the server will send to any individual player. Set to -1 to disable this limit.") ++ public double playerMaxChunkSendRate = 75.0; ++ ++ @Comment( ++ "The maximum rate at which chunks will load for any individual player. " + ++ "Note that this setting also affects chunk generations, since a chunk load is always first issued to test if a" + ++ "chunk is already generated. Set to -1 to disable this limit." ++ ) ++ public double playerMaxChunkLoadRate = 100.0; ++ ++ @Comment("The maximum rate at which chunks will generate for any individual player. Set to -1 to disable this limit.") ++ public double playerMaxChunkGenerateRate = -1.0; ++ } ++ ++ public ChunkLoadingAdvanced chunkLoadingAdvanced; ++ ++ public class ChunkLoadingAdvanced extends ConfigurationPart { ++ @Comment( ++ "Set to true if the server will match the chunk send radius that clients have configured" + ++ "in their view distance settings if the client is less-than the server's send distance." ++ ) ++ public boolean autoConfigSendDistance = true; ++ ++ @Comment( ++ "Specifies the maximum amount of concurrent chunk loads that an individual player can have." + ++ "Set to 0 to let the server configure it automatically per player, or set it to -1 to disable the limit." ++ ) ++ public int playerMaxConcurrentChunkLoads = 0; ++ ++ @Comment( ++ "Specifies the maximum amount of concurrent chunk generations that an individual player can have." + ++ "Set to 0 to let the server configure it automatically per player, or set it to -1 to disable the limit." ++ ) ++ public int playerMaxConcurrentChunkGenerates = 0; ++ } + } +diff --git a/src/main/java/io/papermc/paper/util/IntervalledCounter.java b/src/main/java/io/papermc/paper/util/IntervalledCounter.java +index cea9c098ade00ee87b8efc8164ab72f5279758f0..197224e31175252d8438a8df585bbb65f2288d7f 100644 +--- a/src/main/java/io/papermc/paper/util/IntervalledCounter.java ++++ b/src/main/java/io/papermc/paper/util/IntervalledCounter.java +@@ -2,6 +2,8 @@ package io.papermc.paper.util; + + public final class IntervalledCounter { + ++ private static final int INITIAL_SIZE = 8; ++ + protected long[] times; + protected long[] counts; + protected final long interval; +@@ -11,8 +13,8 @@ public final class IntervalledCounter { + protected int tail; // exclusive + + public IntervalledCounter(final long interval) { +- this.times = new long[8]; +- this.counts = new long[8]; ++ this.times = new long[INITIAL_SIZE]; ++ this.counts = new long[INITIAL_SIZE]; + this.interval = interval; + } + +@@ -67,13 +69,13 @@ public final class IntervalledCounter { + this.tail = nextTail; + } + +- public void updateAndAdd(final int count) { ++ public void updateAndAdd(final long count) { + final long currTime = System.nanoTime(); + this.updateCurrentTime(currTime); + this.addTime(currTime, count); + } + +- public void updateAndAdd(final int count, final long currTime) { ++ public void updateAndAdd(final long count, final long currTime) { + this.updateCurrentTime(currTime); + this.addTime(currTime, count); + } +@@ -93,9 +95,13 @@ public final class IntervalledCounter { + this.tail = size; + + if (tail >= head) { ++ // sequentially ordered from [head, tail) + System.arraycopy(oldElements, head, newElements, 0, size); + System.arraycopy(oldCounts, head, newCounts, 0, size); + } else { ++ // ordered from [head, length) ++ // then followed by [0, tail) ++ + System.arraycopy(oldElements, head, newElements, 0, oldElements.length - head); + System.arraycopy(oldElements, 0, newElements, oldElements.length - head, tail); + +@@ -106,10 +112,18 @@ public final class IntervalledCounter { + + // returns in units per second + public double getRate() { +- return this.size() / (this.interval * 1.0e-9); ++ return (double)this.sum / ((double)this.interval * 1.0E-9); ++ } ++ ++ public long getInterval() { ++ return this.interval; + } + +- public long size() { ++ public long getSum() { + return this.sum; + } ++ ++ public int totalDataPoints() { ++ return this.tail >= this.head ? (this.tail - this.head) : (this.tail + (this.counts.length - this.head)); ++ } + } diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index 902317d2dc198a1cbfc679810bcb2173644354cb..d58d44faa40be2421f4cb54740a3abdbad72875c 100644 +index 902317d2dc198a1cbfc679810bcb2173644354cb..2e830847155e7c43ef411d28e81592c21446143b 100644 --- a/src/main/java/io/papermc/paper/util/MCUtil.java +++ b/src/main/java/io/papermc/paper/util/MCUtil.java @@ -2,16 +2,29 @@ package io.papermc.paper.util; @@ -11944,8 +14413,8 @@ index 902317d2dc198a1cbfc679810bcb2173644354cb..d58d44faa40be2421f4cb54740a3abdb + + worldData.addProperty("is-loaded", loadedWorlds.contains(bukkitWorld)); + worldData.addProperty("name", world.getWorld().getName()); -+ worldData.addProperty("view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance()); // Paper - replace chunk loader system -+ worldData.addProperty("tick-view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance()); // Paper - replace chunk loader system ++ worldData.addProperty("view-distance", world.getWorld().getViewDistance()); // Paper - replace chunk loader system ++ worldData.addProperty("tick-view-distance", world.getWorld().getSimulationDistance()); // Paper - replace chunk loader system + worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); + worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16); + @@ -12913,7 +15382,7 @@ index 51eac8b7177db66c005e4eaca689cf96d10edeaa..4f55f04812fe0306acfc4be45189f1f6 } diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841dbd666f1 100644 +index 4620e64d8eb81520b75fbfbc64603e5887c7b016..4b87f5d899e5ac033d78ccdbca21c9c50c46dcef 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -48,17 +48,15 @@ public class ChunkHolder { @@ -12963,7 +15432,7 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 // Paper start public void onChunkAdd() { -@@ -82,148 +94,106 @@ public class ChunkHolder { +@@ -82,148 +94,130 @@ public class ChunkHolder { } // Paper end @@ -12975,6 +15444,25 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 - this.chunkToSave = CompletableFuture.completedFuture(null); // CraftBukkit - decompile error + public final io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder; // Paper - rewrite chunk system + ++ // Paper start - replace player chunk loader ++ private final com.destroystokyo.paper.util.maplist.ReferenceList playersSentChunkTo = new com.destroystokyo.paper.util.maplist.ReferenceList<>(); ++ ++ public void addPlayer(ServerPlayer player) { ++ if (!this.playersSentChunkTo.add(player)) { ++ throw new IllegalStateException("Already sent chunk " + this.pos + " in world '" + this.chunkMap.level.getWorld().getName() + "' to player " + player); ++ } ++ } ++ ++ public void removePlayer(ServerPlayer player) { ++ if (!this.playersSentChunkTo.remove(player)) { ++ throw new IllegalStateException("Have not sent chunk " + this.pos + " in world '" + this.chunkMap.level.getWorld().getName() + "' to player " + player); ++ } ++ } ++ ++ public boolean hasChunkBeenSent() { ++ return this.playersSentChunkTo.size() != 0; ++ } ++ // Paper end - replace player chunk loader + public ChunkHolder(ChunkPos pos, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.PlayerProvider playersWatchingChunkProvider, io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder) { // Paper - rewrite chunk system + this.newChunkHolder = newChunkHolder; // Paper - rewrite chunk system this.chunkToSaveHistory = null; @@ -13147,11 +15635,16 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 public void blockChanged(BlockPos pos) { - LevelChunk chunk = this.getTickingChunk(); ++ // Paper start - replace player chunk loader ++ if (this.playersSentChunkTo.size() == 0) { ++ return; ++ } ++ // Paper end - replace player chunk loader + LevelChunk chunk = this.getSendingChunk(); // Paper - no-tick view distance if (chunk != null) { int i = this.levelHeightAccessor.getSectionIndex(pos.getY()); -@@ -239,14 +209,15 @@ public class ChunkHolder { +@@ -239,16 +233,17 @@ public class ChunkHolder { } public void sectionLightChanged(LightLayer lightType, int y) { @@ -13169,9 +15662,12 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 + LevelChunk chunk = this.getSendingChunk(); + // Paper end - no-tick view distance - if (chunk != null) { +- if (chunk != null) { ++ if (this.playersSentChunkTo.size() != 0 && chunk != null) { // Paper - replace player chunk loader int j = this.lightEngine.getMinLightSection(); -@@ -273,7 +244,7 @@ public class ChunkHolder { + int k = this.lightEngine.getMaxLightSection(); + +@@ -273,7 +268,7 @@ public class ChunkHolder { List list; if (!this.skyChangedLightSectionFilter.isEmpty() || !this.blockChangedLightSectionFilter.isEmpty()) { @@ -13180,7 +15676,7 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 if (!list.isEmpty()) { ClientboundLightUpdatePacket packetplayoutlightupdate = new ClientboundLightUpdatePacket(chunk.getPos(), this.lightEngine, this.skyChangedLightSectionFilter, this.blockChangedLightSectionFilter); -@@ -285,7 +256,7 @@ public class ChunkHolder { +@@ -285,7 +280,7 @@ public class ChunkHolder { } if (this.hasChangedSections) { @@ -13189,7 +15685,7 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 for (int i = 0; i < this.changedBlocksPerSection.length; ++i) { ShortSet shortset = this.changedBlocksPerSection[i]; -@@ -343,67 +314,48 @@ public class ChunkHolder { +@@ -343,67 +338,35 @@ public class ChunkHolder { } @@ -13208,31 +15704,22 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 - - if (either == null) { - String s = "value in future for status: " + targetStatus + " was incorrectly set to null at chunk: " + this.pos; -+ // Paper start - rewrite chunk system -+ public List getPlayers(boolean onlyOnWatchDistanceEdge){ -+ // Paper start - per player view distance -+ List ret = new java.util.ArrayList<>(); -+ // there can be potential desync with player's last mapped section and the view distance map, so use the -+ // view distance map here. -+ com.destroystokyo.paper.util.misc.PlayerAreaMap viewDistanceMap = this.chunkMap.playerChunkManager.broadcastMap; // Paper - replace old player chunk manager -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet players = viewDistanceMap.getObjectsInRange(this.pos); -+ if (players == null) { -+ return ret; -+ } - +- - throw chunkStorage.debugFuturesAndCreateReportedException(new IllegalStateException("null value previously set for chunk status"), s); -+ Object[] backingSet = players.getBackingSet(); -+ for (int i = 0, len = backingSet.length; i < len; ++i) { -+ if (!(backingSet[i] instanceof ServerPlayer player)) { -+ continue; - } +- } - - if (either == ChunkHolder.NOT_DONE_YET || either.right().isEmpty()) { - return completablefuture; -+ if (!this.chunkMap.playerChunkManager.isChunkSent(player, this.pos.x, this.pos.z, onlyOnWatchDistanceEdge)) { ++ // Paper start - rewrite chunk system ++ public List getPlayers(boolean onlyOnWatchDistanceEdge){ ++ List ret = new java.util.ArrayList<>(); ++ for (int i = 0, len = this.playersSentChunkTo.size(); i < len; ++i) { ++ ServerPlayer player = this.playersSentChunkTo.getUnchecked(i); ++ if (onlyOnWatchDistanceEdge && !this.chunkMap.level.playerChunkLoader.isChunkSent(player, this.pos.x, this.pos.z, onlyOnWatchDistanceEdge)) { + continue; } -- } ++ ret.add(player); + } - if (ChunkLevel.generationStatus(this.ticketLevel).isOrAfter(targetStatus)) { - CompletableFuture> completablefuture1 = chunkStorage.schedule(this, targetStatus); @@ -13242,9 +15729,9 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 - return completablefuture1; - } else { - return completablefuture == null ? ChunkHolder.UNLOADED_CHUNK_FUTURE : completablefuture; -+ ret.add(player); - } -- } +- } ++ return ret; + } - protected void addSaveDependency(String thenDesc, CompletableFuture then) { - if (this.chunkToSaveHistory != null) { @@ -13254,18 +15741,16 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 - this.chunkToSave = this.chunkToSave.thenCombine(then, (ichunkaccess, object) -> { - return ichunkaccess; - }); -+ return ret; ++ public void broadcast(Packet packet, boolean onlyOnWatchDistanceEdge) { ++ this.broadcast(this.getPlayers(onlyOnWatchDistanceEdge), packet); } ++ // Paper end - rewrite chunk system - private void updateChunkToSave(CompletableFuture> then, String thenDesc) { - if (this.chunkToSaveHistory != null) { - this.chunkToSaveHistory.push(new ChunkHolder.ChunkSaveDebug(Thread.currentThread(), then, thenDesc)); - } -+ public void broadcast(Packet packet, boolean onlyOnWatchDistanceEdge) { -+ this.broadcast(this.getPlayers(onlyOnWatchDistanceEdge), packet); -+ } -+ // Paper end - rewrite chunk system - +- - this.chunkToSave = this.chunkToSave.thenCombine(then, (ichunkaccess, either) -> { - return (ChunkAccess) either.map((ichunkaccess1) -> { - return ichunkaccess1; @@ -13286,7 +15771,7 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 } public final ChunkPos getPos() { // Paper - final for inline -@@ -411,240 +363,27 @@ public class ChunkHolder { +@@ -411,240 +374,27 @@ public class ChunkHolder { } public final int getTicketLevel() { // Paper - final for inline @@ -13536,7 +16021,7 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 } @FunctionalInterface -@@ -682,15 +421,15 @@ public class ChunkHolder { +@@ -682,15 +432,15 @@ public class ChunkHolder { // Paper start public final boolean isEntityTickingReady() { @@ -13556,7 +16041,7 @@ index 4620e64d8eb81520b75fbfbc64603e5887c7b016..6b6d31e76f48a0de33ac528f990ce841 // Paper end } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141a2de3a58 100644 +index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..a502d293cedb2f507e6cf1792429b36685ed1910 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -127,10 +127,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -13591,7 +16076,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 private final String storageName; private final PlayerMap playerMap; public final Int2ObjectMap entityMap; -@@ -157,37 +152,21 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -157,37 +152,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private final Queue unloadQueue; int viewDistance; @@ -13619,29 +16104,28 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 // Paper start - distance maps private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); -+ public final io.papermc.paper.chunk.PlayerChunkLoader playerChunkManager = new io.papermc.paper.chunk.PlayerChunkLoader(this, this.pooledLinkedPlayerHashSets); // Paper - replace chunk loader void addPlayerToDistanceMaps(ServerPlayer player) { -+ this.playerChunkManager.addPlayer(player); // Paper - replace chunk loader ++ this.level.playerChunkLoader.addPlayer(player); // Paper - replace chunk loader int chunkX = MCUtil.getChunkCoordinate(player.getX()); int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated } void removePlayerFromDistanceMaps(ServerPlayer player) { -+ this.playerChunkManager.removePlayer(player); // Paper - replace chunk loader ++ this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader } -@@ -195,6 +174,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -195,6 +173,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int chunkX = MCUtil.getChunkCoordinate(player.getX()); int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated -+ this.playerChunkManager.updatePlayer(player); // Paper - replace chunk loader ++ this.level.playerChunkLoader.updatePlayer(player); // Paper - replace chunk loader } // Paper end // Paper start -@@ -224,16 +204,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -224,16 +203,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) { @@ -13660,7 +16144,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 this.tickingGenerated = new AtomicInteger(); this.playerMap = new PlayerMap(); this.entityMap = new Int2ObjectOpenHashMap(); -@@ -264,19 +241,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -264,19 +240,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.chunkGeneratorState = chunkGenerator.createState(iregistrycustom.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, j, world.spigotConfig); // Spigot this.mainThreadExecutor = mainThreadExecutor; @@ -13685,7 +16169,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor); this.overworldDataStorage = persistentStateManagerFactory; this.poiManager = new PoiManager(path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); -@@ -340,20 +315,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -340,20 +314,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Nullable protected ChunkHolder getUpdatingChunkIfPresent(long pos) { @@ -13715,7 +16199,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 } public String getChunkDebugData(ChunkPos chunkPos) { -@@ -391,84 +368,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -391,84 +367,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper end private CompletableFuture, ChunkHolder.ChunkLoadingFailure>> getChunkRangeFuture(ChunkHolder centerChunk, int margin, IntFunction distanceToStatus) { @@ -13801,7 +16285,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 } public ReportedException debugFuturesAndCreateReportedException(IllegalStateException exception, String details) { -@@ -498,263 +398,72 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -498,263 +397,72 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public CompletableFuture> prepareEntityTickingChunk(ChunkHolder chunk) { @@ -14085,7 +16569,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 return nbt.contains("Status", 8); } -@@ -790,54 +499,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -790,54 +498,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } private CompletableFuture> scheduleChunkGeneration(ChunkHolder holder, ChunkStatus requiredStatus) { @@ -14141,7 +16625,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 } protected void releaseLightTicket(ChunkPos pos) { -@@ -848,7 +510,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -848,7 +509,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider })); } @@ -14150,7 +16634,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 ChunkStatus chunkstatus1; if (distance == 0) { -@@ -860,7 +522,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -860,7 +521,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return chunkstatus1; } @@ -14159,7 +16643,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 if (!nbt.isEmpty()) { // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(nbt, world).filter((entity) -> { -@@ -882,93 +544,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -882,93 +543,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } private CompletableFuture> protoChunkToFullChunk(ChunkHolder chunkHolder) { @@ -14256,7 +16740,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 } public int getTickingGenerated() { -@@ -976,94 +560,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -976,94 +559,26 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } private boolean saveChunkIfNeeded(ChunkHolder chunkHolder) { @@ -14345,21 +16829,24 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 - } - - ChunkStatus.ChunkType chunkstatus_type = ChunkSerializer.getChunkTypeFromTag(nbttagcompound); -- ++ throw new UnsupportedOperationException(); // Paper - rewrite chunk system ++ } + - return this.markPosition(pos, chunkstatus_type) == 1; - } -+ throw new UnsupportedOperationException(); // Paper - rewrite chunk system - } - + // Paper start - replace player loader system + public void setTickViewDistance(int distance) { -+ this.playerChunkManager.setTickDistance(distance); ++ this.level.playerChunkLoader.setTickDistance(distance); + } + ++ public void setSendViewDistance(int distance) { ++ this.level.playerChunkLoader.setSendDistance(distance); + } + // Paper end - replace player loader system public void setViewDistance(int watchDistance) { int j = Mth.clamp(watchDistance, 2, 32); -@@ -1071,33 +583,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1071,35 +586,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int k = this.viewDistance; this.viewDistance = j; @@ -14379,24 +16866,50 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 - this.updateChunkTracking(entityplayer, chunkcoordintpair, mutableobject, flag, flag1); - }); - } -+ this.playerChunkManager.setLoadDistance(this.viewDistance); // Paper - replace player loader system ++ this.level.playerChunkLoader.setLoadDistance(this.viewDistance); // Paper - replace player loader system } } - protected void updateChunkTracking(ServerPlayer player, ChunkPos pos, MutableObject packet, boolean oldWithinViewDistance, boolean newWithinViewDistance) { + public void updateChunkTracking(ServerPlayer player, ChunkPos pos, MutableObject packet, boolean oldWithinViewDistance, boolean newWithinViewDistance) { // Paper - public ++ io.papermc.paper.util.TickThread.ensureTickThread(this.level, pos, "May not update chunk tracking for chunk async"); // Paper - replace chunk loader system ++ io.papermc.paper.util.TickThread.ensureTickThread(player, "May not update chunk tracking for player async"); // Paper - replace chunk loader system if (player.level() == this.level) { ++ ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); // Paper - replace chunk loader system - move up if (newWithinViewDistance && !oldWithinViewDistance) { - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); +- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); ++ // Paper - replace chunk loader system - move up if (playerchunk != null) { - LevelChunk chunk = playerchunk.getTickingChunk(); + LevelChunk chunk = playerchunk.getSendingChunk(); // Paper - replace chunk loader system if (chunk != null) { ++ playerchunk.addPlayer(player); // Paper - replace chunk loader system this.playerLoadedChunk(player, packet, chunk); -@@ -1127,30 +624,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + +@@ -1108,10 +612,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + if (!newWithinViewDistance && oldWithinViewDistance) { ++ // Paper start - replace chunk loader system ++ if (playerchunk != null) { ++ playerchunk.removePlayer(player); ++ } else { ++ LOGGER.warn("ChunkHolder at " + pos + " in world '" + this.level.getWorld().getName() + "' does not exist to untrack chunk for " + player, new Throwable()); ++ } ++ // Paper end - replace chunk loader system + player.untrackChunk(pos); + } + +- } ++ } else { LOGGER.warn("Mismatch in world for chunk " + pos + " in world '" + this.level.getWorld().getName() + "' for player " + player, new Throwable()); } // Paper - replace chunk loader system + } + + public int size() { +@@ -1127,30 +638,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } void dumpChunks(Writer writer) throws IOException { @@ -14428,7 +16941,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 } private static String printFuture(CompletableFuture> future) { -@@ -1169,6 +643,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1169,6 +657,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } @@ -14464,7 +16977,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 private CompletableFuture> readChunk(ChunkPos chunkPos) { return this.read(chunkPos).thenApplyAsync((optional) -> { return optional.map((nbttagcompound) -> this.upgradeChunkTag(nbttagcompound, chunkPos)); // CraftBukkit -@@ -1272,15 +775,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1272,15 +789,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.removePlayerFromDistanceMaps(player); // Paper - distance maps } @@ -14481,7 +16994,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 } -@@ -1288,7 +783,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1288,7 +797,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider SectionPos sectionposition = SectionPos.of((EntityAccess) player); player.setLastSectionPos(sectionposition); @@ -14490,7 +17003,7 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 return sectionposition; } -@@ -1344,65 +839,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1344,44 +853,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int l1; int i2; @@ -14535,48 +17048,36 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 + // Paper - replaced by PlayerChunkLoader this.updateMaps(player); // Paper - distance maps -+ this.playerChunkManager.updatePlayer(player); // Paper - respond to movement immediately - } +@@ -1389,20 +861,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Override public List getPlayers(ChunkPos chunkPos, boolean onlyOnWatchDistanceEdge) { - Set set = this.playerMap.getPlayers(chunkPos.toLong()); - Builder builder = ImmutableList.builder(); - Iterator iterator = set.iterator(); -+ // Paper start - per player view distance -+ // there can be potential desync with player's last mapped section and the view distance map, so use the -+ // view distance map here. -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet players = this.playerChunkManager.broadcastMap.getObjectsInRange(chunkPos); -+ if (players == null) { -+ return java.util.Collections.emptyList(); -+ } - +- - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); - SectionPos sectionposition = entityplayer.getLastSectionPos(); -+ List ret = new java.util.ArrayList<>(players.size()); - +- - if (onlyOnWatchDistanceEdge && ChunkMap.isChunkOnRangeBorder(chunkPos.x, chunkPos.z, sectionposition.x(), sectionposition.z(), this.viewDistance) || !onlyOnWatchDistanceEdge && ChunkMap.isChunkInRange(chunkPos.x, chunkPos.z, sectionposition.x(), sectionposition.z(), this.viewDistance)) { - builder.add(entityplayer); -+ Object[] backingSet = players.getBackingSet(); -+ for (int i = 0, len = backingSet.length; i < len; ++i) { -+ if (!(backingSet[i] instanceof ServerPlayer player)) { -+ continue; -+ } -+ if (!this.playerChunkManager.isChunkSent(player, chunkPos.x, chunkPos.z, onlyOnWatchDistanceEdge)) { -+ continue; - } -+ ret.add(player); +- } ++ // Paper start - per player view distance ++ ChunkHolder holder = this.getVisibleChunkIfPresent(chunkPos.toLong()); ++ if (holder == null) { ++ return new java.util.ArrayList<>(); ++ } else { ++ return holder.getPlayers(onlyOnWatchDistanceEdge); } - +- - return builder.build(); -+ return ret; + // Paper end - per player view distance } public void addEntity(Entity entity) { -@@ -1630,7 +1098,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1630,7 +1096,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Override protected boolean isChunkToRemove(long pos) { @@ -14585,17 +17086,17 @@ index 19bd6f9aee3ccb1af1b010ee51a54aa2d0bf9c84..284393fd4ae0a7562b6bc9b60cf2c141 } @Nullable -@@ -1711,7 +1179,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1711,7 +1177,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot if (player != this.entity) { Vec3 vec3d = player.position().subtract(this.entity.position()); - double d0 = (double) Math.min(this.getEffectiveRange(), ChunkMap.this.viewDistance * 16); -+ double d0 = (double) Math.min(this.getEffectiveRange(), io.papermc.paper.chunk.PlayerChunkLoader.getSendViewDistance(player) * 16); // Paper - per player view distance ++ double d0 = (double) Math.min(this.getEffectiveRange(), io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player) * 16); // Paper - per player view distance double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; double d2 = d0 * d0; boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player); diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index f3c9a3dbb6f0e6f825b7477c89ed72ed52845419..32a07573ee23f01c98e684aefb45ff72802c9db6 100644 +index f3c9a3dbb6f0e6f825b7477c89ed72ed52845419..20d600d29c2f2e47c798721d1f151e625b12acc3 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -39,65 +39,28 @@ import org.slf4j.Logger; @@ -14900,13 +17401,13 @@ index f3c9a3dbb6f0e6f825b7477c89ed72ed52845419..32a07573ee23f01c98e684aefb45ff72 protected void updatePlayerTickets(int viewDistance) { - this.playerTicketManager.updateViewDistance(viewDistance); -+ this.chunkMap.playerChunkManager.setTargetNoTickViewDistance(viewDistance); // Paper - route to player chunk manager ++ this.chunkMap.setViewDistance(viewDistance);// Paper - route to player chunk manager } // Paper start public int getSimulationDistance() { - return this.simulationDistance; -+ return this.chunkMap.playerChunkManager.getTargetTickViewDistance(); // Paper - route to player chunk manager ++ return this.chunkMap.level.playerChunkLoader.getAPITickDistance(); } // Paper end @@ -14916,7 +17417,7 @@ index f3c9a3dbb6f0e6f825b7477c89ed72ed52845419..32a07573ee23f01c98e684aefb45ff72 - this.tickingTicketsTracker.replacePlayerTicketsLevel(this.getPlayerTicketLevel()); - } - -+ this.chunkMap.playerChunkManager.setTargetTickViewDistance(simulationDistance); // Paper - route to player chunk manager ++ this.chunkMap.level.playerChunkLoader.setTickDistance(simulationDistance); // Paper - route to player chunk manager } public int getNaturalSpawnChunkCount() { @@ -15054,7 +17555,7 @@ index f3c9a3dbb6f0e6f825b7477c89ed72ed52845419..32a07573ee23f01c98e684aefb45ff72 + */ // Paper - rewrite chunk system } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index fc1afda5a60ab0f3c275f849d8af08d308b36c3f..bb7b7f904639ac964f9c2d1bd5a660d8b397f647 100644 +index fc1afda5a60ab0f3c275f849d8af08d308b36c3f..caff28e2446177d622c999b84d8889fbf61d0b3d 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -367,7 +367,7 @@ public class ServerChunkCache extends ChunkSource { @@ -15329,7 +17830,7 @@ index fc1afda5a60ab0f3c275f849d8af08d308b36c3f..bb7b7f904639ac964f9c2d1bd5a660d8 this.level.getProfiler().popPush("chunks"); if (tickChunks) { this.level.timings.chunks.startTiming(); // Paper - timings -+ this.chunkMap.playerChunkManager.tick(); // Paper - this is mostly is to account for view distance changes ++ this.chunkMap.level.playerChunkLoader.tick(); // Paper - replace player chunk loader - this is mostly required to account for view distance changes this.tickChunks(); this.level.timings.chunks.stopTiming(); // Paper - timings } @@ -15352,7 +17853,7 @@ index fc1afda5a60ab0f3c275f849d8af08d308b36c3f..bb7b7f904639ac964f9c2d1bd5a660d8 // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task public boolean pollTask() { - try { -+ ServerChunkCache.this.chunkMap.playerChunkManager.tickMidTick(); ++ // Paper - replace player chunk loader if (ServerChunkCache.this.runDistanceManagerUpdates()) { return true; - } else { @@ -15368,7 +17869,7 @@ index fc1afda5a60ab0f3c275f849d8af08d308b36c3f..bb7b7f904639ac964f9c2d1bd5a660d8 } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32cc483db56 100644 +index 7cb5abfa89f842194325d26c6e95b49460c5968f..62a95a0fac59683948f34b202e6e3859b6652d6d 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -194,7 +194,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -15380,7 +17881,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c private final GameEventDispatcher gameEventDispatcher; public boolean noSave; private final SleepStatus sleepStatus; -@@ -320,7 +320,108 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -320,7 +320,150 @@ public class ServerLevel extends Level implements WorldGenLevel { } } } @@ -15487,10 +17988,52 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c + return this.entityLookup; + } + // Paper end - rewrite chunk system ++ ++ public final io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader playerChunkLoader = new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader(this); ++ private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); ++ ++ public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances getViewDistances() { ++ return this.viewDistances.get(); ++ } ++ ++ private void updateViewDistance(final java.util.function.Function update) { ++ for (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances curr = this.viewDistances.get();;) { ++ if (this.viewDistances.compareAndSet(curr, update.apply(curr))) { ++ return; ++ } ++ } ++ } ++ ++ public void setTickViewDistance(final int distance) { ++ if ((distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE)) { ++ throw new IllegalArgumentException("Tick view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE) + ", got: " + distance); ++ } ++ this.updateViewDistance((input) -> { ++ return input.setTickViewDistance(distance); ++ }); ++ } ++ ++ public void setLoadViewDistance(final int distance) { ++ if (distance != -1 && (distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1)) { ++ throw new IllegalArgumentException("Load view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1) + " or -1, got: " + distance); ++ } ++ this.updateViewDistance((input) -> { ++ return input.setLoadViewDistance(distance); ++ }); ++ } ++ ++ public void setSendViewDistance(final int distance) { ++ if (distance != -1 && (distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1)) { ++ throw new IllegalArgumentException("Send view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1) + " or -1, got: " + distance); ++ } ++ this.updateViewDistance((input) -> { ++ return input.setSendViewDistance(distance); ++ }); ++ } // Add env and gen to constructor, IWorldDataServer -> WorldDataServer public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { -@@ -364,16 +465,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -364,16 +507,16 @@ public class ServerLevel extends Level implements WorldGenLevel { // CraftBukkit end boolean flag2 = minecraftserver.forceSynchronousWrites(); DataFixer datafixer = minecraftserver.getFixerUpper(); @@ -15512,7 +18055,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c return minecraftserver.overworld().getDataStorage(); }); this.chunkSource.getGeneratorState().ensureStructuresGenerated(); -@@ -410,6 +511,9 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -410,6 +553,9 @@ public class ServerLevel extends Level implements WorldGenLevel { }, "random_sequences"); }); this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit @@ -15522,7 +18065,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c } /** @deprecated */ -@@ -520,7 +624,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -520,7 +666,7 @@ public class ServerLevel extends Level implements WorldGenLevel { gameprofilerfiller.push("checkDespawn"); entity.checkDespawn(); gameprofilerfiller.pop(); @@ -15531,7 +18074,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c Entity entity1 = entity.getVehicle(); if (entity1 != null) { -@@ -545,13 +649,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -545,13 +691,16 @@ public class ServerLevel extends Level implements WorldGenLevel { } gameprofilerfiller.push("entityManagement"); @@ -15550,7 +18093,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c } protected void tickTime() { -@@ -1012,6 +1119,11 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1012,6 +1161,11 @@ public class ServerLevel extends Level implements WorldGenLevel { } public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) { @@ -15562,7 +18105,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c ServerChunkCache chunkproviderserver = this.getChunkSource(); if (!savingDisabled) { -@@ -1027,16 +1139,13 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1027,16 +1181,13 @@ public class ServerLevel extends Level implements WorldGenLevel { } timings.worldSaveChunks.startTiming(); // Paper @@ -15583,7 +18126,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c // CraftBukkit start - moved from MinecraftServer.saveChunks ServerLevel worldserver1 = this; -@@ -1172,7 +1281,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1172,7 +1323,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.removePlayerImmediately((ServerPlayer) entity, Entity.RemovalReason.DISCARDED); } @@ -15592,7 +18135,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c } // CraftBukkit start -@@ -1188,7 +1297,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1188,7 +1339,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } // CraftBukkit end @@ -15601,7 +18144,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c } } -@@ -1200,10 +1309,10 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1200,10 +1351,10 @@ public class ServerLevel extends Level implements WorldGenLevel { public boolean tryAddFreshEntityWithPassengers(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { // CraftBukkit end Stream stream = entity.getSelfAndPassengers().map(Entity::getUUID); // CraftBukkit - decompile error @@ -15615,7 +18158,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c return false; } else { this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit -@@ -1723,7 +1832,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1723,7 +1874,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } } @@ -15624,7 +18167,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c bufferedwriter.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size())); bufferedwriter.write(String.format(Locale.ROOT, "block_ticks: %d\n", this.getBlockTicks().count())); bufferedwriter.write(String.format(Locale.ROOT, "fluid_ticks: %d\n", this.getFluidTicks().count())); -@@ -1772,7 +1881,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1772,7 +1923,7 @@ public class ServerLevel extends Level implements WorldGenLevel { BufferedWriter bufferedwriter2 = Files.newBufferedWriter(path1); try { @@ -15633,7 +18176,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c } catch (Throwable throwable4) { if (bufferedwriter2 != null) { try { -@@ -1793,7 +1902,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1793,7 +1944,7 @@ public class ServerLevel extends Level implements WorldGenLevel { BufferedWriter bufferedwriter3 = Files.newBufferedWriter(path2); try { @@ -15642,7 +18185,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c } catch (Throwable throwable6) { if (bufferedwriter3 != null) { try { -@@ -1935,7 +2044,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1935,7 +2086,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @VisibleForTesting public String getWatchdogStats() { @@ -15651,7 +18194,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c return BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString(); }), this.blockEntityTickers.size(), ServerLevel.getTypeCount(this.blockEntityTickers, TickingBlockEntity::getType), this.getBlockTicks().count(), this.getFluidTicks().count(), this.gatherChunkSourceStats()); } -@@ -1995,15 +2104,15 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1995,15 +2146,15 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public LevelEntityGetter getEntities() { org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot @@ -15670,7 +18213,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c } public void startTickingChunk(LevelChunk chunk) { -@@ -2019,34 +2128,49 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2019,34 +2170,49 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public void close() throws IOException { super.close(); @@ -15727,8 +18270,61 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..d7172df2489f2eb325120d950dcff32c } @Override +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 5872ead2fe3a64f02f8bc36603fbb856728fd255..32ef9f1ae0c35e927133572ebb6fbf50b0729a63 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -260,6 +260,48 @@ public class ServerPlayer extends Player { + public boolean isRealPlayer; // Paper + public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet cachedSingleHashSet; // Paper + ++ private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); ++ public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader; ++ ++ public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances getViewDistances() { ++ return this.viewDistances.get(); ++ } ++ ++ private void updateViewDistance(final java.util.function.Function update) { ++ for (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances curr = this.viewDistances.get();;) { ++ if (this.viewDistances.compareAndSet(curr, update.apply(curr))) { ++ return; ++ } ++ } ++ } ++ ++ public void setTickViewDistance(final int distance) { ++ if ((distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE)) { ++ throw new IllegalArgumentException("Tick view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE) + ", got: " + distance); ++ } ++ this.updateViewDistance((input) -> { ++ return input.setTickViewDistance(distance); ++ }); ++ } ++ ++ public void setLoadViewDistance(final int distance) { ++ if (distance != -1 && (distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1)) { ++ throw new IllegalArgumentException("Load view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1) + " or -1, got: " + distance); ++ } ++ this.updateViewDistance((input) -> { ++ return input.setLoadViewDistance(distance); ++ }); ++ } ++ ++ public void setSendViewDistance(final int distance) { ++ if (distance != -1 && (distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1)) { ++ throw new IllegalArgumentException("Send view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1) + " or -1, got: " + distance); ++ } ++ this.updateViewDistance((input) -> { ++ return input.setSendViewDistance(distance); ++ }); ++ } ++ + public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile) { + super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); + this.chatVisibility = ChatVisiblity.FULL; diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -index 481272124b7589cff0aa05b6df5b7e6f1d539414..c709e27a00d8617f9a3346f85bd88ce47baa9c76 100644 +index 481272124b7589cff0aa05b6df5b7e6f1d539414..b4be02ec4bb77059f79d3e4d6a6f1ee4843a01f9 100644 --- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java +++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java @@ -37,15 +37,12 @@ import net.minecraft.world.level.chunk.ChunkStatus; @@ -15765,7 +18361,7 @@ index 481272124b7589cff0aa05b6df5b7e6f1d539414..c709e27a00d8617f9a3346f85bd88ce4 } - this.taskMailbox.tell(() -> { -+ this.chunkMap.level.chunkTaskScheduler.lightExecutor.queueRunnable(() -> { // Paper - rewrite chunk system ++ this.chunkMap.level.chunkTaskScheduler.radiusAwareScheduler.queueInfiniteRadiusTask(() -> { // Paper - rewrite chunk system this.theLightEngine.relightChunks(chunks, (ChunkPos chunkPos) -> { chunkLightCallback.accept(chunkPos); ((java.util.concurrent.Executor)((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().mainThreadProcessor).execute(() -> { @@ -15996,7 +18592,7 @@ index 403f7c7f31e0072b0cad0706bc981ece24733a1d..d72e8df4f99b6219ea305742f0cf8d1c StringReader stringreader = new StringReader(packet.getCommand()); diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 90c73b9075489242556a7ba749618e20c0ed0c4d..d4f44635b3cb7ac890ea89b6f4454fa9d4375c08 100644 +index 90c73b9075489242556a7ba749618e20c0ed0c4d..0338a6b245ee482d470f5a80da712679ab9890fa 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -262,7 +262,7 @@ public abstract class PlayerList { @@ -16004,7 +18600,7 @@ index 90c73b9075489242556a7ba749618e20c0ed0c4d..d4f44635b3cb7ac890ea89b6f4454fa9 // Spigot - view distance - playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), this.server.levelKeys(), this.synchronizedRegistries, worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), this.getMaxPlayers(), worldserver1.spigotConfig.viewDistance, worldserver1.spigotConfig.simulationDistance, flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat(), player.getLastDeathLocation(), player.getPortalCooldown())); -+ playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), this.server.levelKeys(), this.synchronizedRegistries, worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), this.getMaxPlayers(), worldserver1.getChunkSource().chunkMap.playerChunkManager.getTargetSendDistance(), worldserver1.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance(), flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat(), player.getLastDeathLocation(), player.getPortalCooldown())); // Paper - replace old player chunk management ++ playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), this.server.levelKeys(), this.synchronizedRegistries, worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), this.getMaxPlayers(), worldserver1.getWorld().getSendViewDistance(), worldserver1.getWorld().getSimulationDistance(), flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat(), player.getLastDeathLocation(), player.getPortalCooldown())); // Paper - replace old player chunk management player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit playerconnection.send(new ClientboundUpdateEnabledFeaturesPacket(FeatureFlags.REGISTRY.toNames(worldserver1.enabledFeatures()))); playerconnection.send(new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, (new FriendlyByteBuf(Unpooled.buffer())).writeUtf(this.getServer().getServerModName()))); @@ -16014,8 +18610,8 @@ index 90c73b9075489242556a7ba749618e20c0ed0c4d..d4f44635b3cb7ac890ea89b6f4454fa9 entityplayer1.connection.send(new ClientboundRespawnPacket(worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), entityplayer1.gameMode.getGameModeForPlayer(), entityplayer1.gameMode.getPreviousGameModeForPlayer(), worldserver1.isDebug(), worldserver1.isFlat(), (byte) i, entityplayer1.getLastDeathLocation(), entityplayer1.getPortalCooldown())); - entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.spigotConfig.viewDistance)); // Spigot - entityplayer1.connection.send(new ClientboundSetSimulationDistancePacket(worldserver1.spigotConfig.simulationDistance)); // Spigot -+ entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.getChunkSource().chunkMap.playerChunkManager.getTargetSendDistance())); // Spigot // Paper - replace old player chunk management -+ entityplayer1.connection.send(new ClientboundSetSimulationDistancePacket(worldserver1.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance())); // Spigot // Paper - replace old player chunk management ++ entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.getWorld().getSendViewDistance())); // Spigot // Paper - replace old player chunk management ++ entityplayer1.connection.send(new ClientboundSetSimulationDistancePacket(worldserver1.getWorld().getSimulationDistance())); // Spigot // Paper - replace old player chunk management entityplayer1.spawnIn(worldserver1); entityplayer1.unsetRemoved(); entityplayer1.connection.teleport(CraftLocation.toBukkit(entityplayer1.position(), worldserver1.getWorld(), entityplayer1.getYRot(), entityplayer1.getXRot())); @@ -16271,7 +18867,7 @@ index f668a80c6bff67bf766207985c1af73f09e1bd1c..7f6a90fab14d6880f2784e1c62eb2f3c @Override diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -index b18b896c624d5cadc02b1db9d011d82124d61d54..f10ba4211cbdcc4f4ce3585c7cb3f80185e13b73 100644 +index b18b896c624d5cadc02b1db9d011d82124d61d54..6f2c7baea0d1ac7813c7b85e1f5558573745762c 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java @@ -38,12 +38,28 @@ import net.minecraft.world.level.chunk.storage.SectionStorage; @@ -16317,7 +18913,7 @@ index b18b896c624d5cadc02b1db9d011d82124d61d54..f10ba4211cbdcc4f4ce3585c7cb3f801 } boolean isVillageCenter(long pos) { -@@ -195,21 +211,107 @@ public class PoiManager extends SectionStorage { +@@ -195,21 +211,118 @@ public class PoiManager extends SectionStorage { @Override public void tick(BooleanSupplier shouldKeepTicking) { @@ -16347,8 +18943,8 @@ index b18b896c624d5cadc02b1db9d011d82124d61d54..f10ba4211cbdcc4f4ce3585c7cb3f801 protected void onSectionLoad(long pos) { - this.distanceTracker.update(pos, this.distanceTracker.getLevelFromSource(pos), false); + this.updateDistanceTracking(pos); // Paper - move to new distance tracking util - } - ++ } ++ + // Paper start - rewrite chunk system + @Override + public Optional get(long pos) { @@ -16424,6 +19020,17 @@ index b18b896c624d5cadc02b1db9d011d82124d61d54..f10ba4211cbdcc4f4ce3585c7cb3f801 + if (section != null && !section.isEmpty()) { + this.onSectionLoad(SectionPos.asLong(chunkX, sectionY, chunkZ)); + } ++ } + } + ++ public void checkConsistency(net.minecraft.world.level.chunk.ChunkAccess chunk) { ++ int chunkX = chunk.getPos().x; ++ int chunkZ = chunk.getPos().z; ++ int minY = io.papermc.paper.util.WorldUtil.getMinSection(chunk); ++ int maxY = io.papermc.paper.util.WorldUtil.getMaxSection(chunk); ++ LevelChunkSection[] sections = chunk.getSections(); ++ for (int section = minY; section <= maxY; ++section) { ++ this.checkConsistencyWithBlocks(SectionPos.of(chunkX, section, chunkZ), sections[section - minY]); + } + } + // Paper end - rewrite chunk system @@ -16431,7 +19038,7 @@ index b18b896c624d5cadc02b1db9d011d82124d61d54..f10ba4211cbdcc4f4ce3585c7cb3f801 public void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection chunkSection) { Util.ifElse(this.getOrLoad(sectionPos.asLong()), (poiSet) -> { poiSet.refresh((populator) -> { -@@ -248,7 +350,7 @@ public class PoiManager extends SectionStorage { +@@ -248,7 +361,7 @@ public class PoiManager extends SectionStorage { }).map((pair) -> { return pair.getFirst().chunk(); }).filter((chunkPos) -> { @@ -16440,7 +19047,7 @@ index b18b896c624d5cadc02b1db9d011d82124d61d54..f10ba4211cbdcc4f4ce3585c7cb3f801 }).forEach((chunkPos) -> { world.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY); }); -@@ -264,7 +366,7 @@ public class PoiManager extends SectionStorage { +@@ -264,7 +377,7 @@ public class PoiManager extends SectionStorage { @Override protected int getLevelFromSource(long id) { @@ -16449,7 +19056,7 @@ index b18b896c624d5cadc02b1db9d011d82124d61d54..f10ba4211cbdcc4f4ce3585c7cb3f801 } @Override -@@ -287,6 +389,35 @@ public class PoiManager extends SectionStorage { +@@ -287,6 +400,35 @@ public class PoiManager extends SectionStorage { } } @@ -16534,7 +19141,7 @@ index 127c4ebedb94631ceac92dbdcd465e904217d715..be6e3e21ad62da01e5e2dd78e300cbc8 List getEntities(EntityTypeTest filter, AABB box, Predicate predicate); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index d87f02c748fe2e5b4ea251f6691e8907a152cb6d..0276c32ef8323bcf82eb3400bb003a93b8a56de0 100644 +index d87f02c748fe2e5b4ea251f6691e8907a152cb6d..5988c0847af4e8f0094328e91f736f25d567db60 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -453,6 +453,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @@ -16543,7 +19150,7 @@ index d87f02c748fe2e5b4ea251f6691e8907a152cb6d..0276c32ef8323bcf82eb3400bb003a93 this.sendBlockUpdated(blockposition, iblockdata1, iblockdata, i); + // Paper start - per player view distance - allow block updates for non-ticking chunks in player view distance + // if copied from above -+ } else if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || ((ServerLevel)this).getChunkSource().chunkMap.playerChunkManager.broadcastMap.getObjectsInRange(io.papermc.paper.util.MCUtil.getCoordinateKey(blockposition)) != null)) { // Paper - replace old player chunk management ++ } else if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0)) { // Paper - replace old player chunk management + ((ServerLevel)this).getChunkSource().blockChanged(blockposition); + // Paper end - per player view distance } @@ -16762,54 +19369,10 @@ index fb5a06a908d2b42bf0530b62ed648548499d9f87..ec55711e912fe6cb8f797c0b21bcef27 public int getIndex() { 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 09999a3f523ce6d652799215d3418284a69042c1..41754f6c8162df07e2b22f4ffcacd8b6158a864e 100644 +index 09999a3f523ce6d652799215d3418284a69042c1..3da04db71d6f33b2f466c11e031e0a11c298379b 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -172,6 +172,43 @@ public class LevelChunk extends ChunkAccess { - - protected void onNeighbourChange(final long bitsetBefore, final long bitsetAfter) { - -+ // Paper start - no-tick view distance -+ ServerChunkCache chunkProviderServer = ((ServerLevel)this.level).getChunkSource(); -+ net.minecraft.server.level.ChunkMap chunkMap = chunkProviderServer.chunkMap; -+ // this code handles the addition of ticking tickets - the distance map handles the removal -+ if (!areNeighboursLoaded(bitsetBefore, 2) && areNeighboursLoaded(bitsetAfter, 2)) { -+ if (chunkMap.playerChunkManager.tickMap.getObjectsInRange(this.coordinateKey) != null) { // Paper - replace old player chunk loading system -+ // now we're ready for entity ticking -+ chunkProviderServer.mainThreadProcessor.execute(() -> { -+ // double check that this condition still holds. -+ if (LevelChunk.this.areNeighboursLoaded(2) && chunkMap.playerChunkManager.tickMap.getObjectsInRange(LevelChunk.this.coordinateKey) != null) { // Paper - replace old player chunk loading system -+ chunkMap.playerChunkManager.onChunkPlayerTickReady(this.chunkPos.x, this.chunkPos.z); // Paper - replace old player chunk -+ chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.PLAYER, LevelChunk.this.chunkPos, 31, LevelChunk.this.chunkPos); // 31 -> entity ticking, TODO check on update -+ } -+ }); -+ } -+ } -+ -+ // this code handles the chunk sending -+ if (!areNeighboursLoaded(bitsetBefore, 1) && areNeighboursLoaded(bitsetAfter, 1)) { -+ // Paper start - replace old player chunk loading system -+ if (chunkMap.playerChunkManager.isChunkNearPlayers(this.chunkPos.x, this.chunkPos.z)) { -+ // the post processing is expensive, so we don't want to run it unless we're actually near -+ // a player. -+ chunkProviderServer.mainThreadProcessor.execute(() -> { -+ if (!LevelChunk.this.areNeighboursLoaded(1)) { -+ return; -+ } -+ LevelChunk.this.postProcessGeneration(); -+ if (!LevelChunk.this.areNeighboursLoaded(1)) { -+ return; -+ } -+ chunkMap.playerChunkManager.onChunkSendReady(this.chunkPos.x, this.chunkPos.z); -+ }); -+ } -+ // Paper end - replace old player chunk loading system -+ } -+ // Paper end - no-tick view distance - } - - public final boolean isAnyNeighborsLoaded() { -@@ -661,9 +698,26 @@ public class LevelChunk extends ChunkAccess { +@@ -661,9 +661,26 @@ public class LevelChunk extends ChunkAccess { } @@ -16839,7 +19402,7 @@ index 09999a3f523ce6d652799215d3418284a69042c1..41754f6c8162df07e2b22f4ffcacd8b6 int chunkX = this.chunkPos.x; int chunkZ = this.chunkPos.z; net.minecraft.server.level.ServerChunkCache chunkProvider = this.level.getChunkSource(); -@@ -678,10 +732,56 @@ public class LevelChunk extends ChunkAccess { +@@ -678,10 +695,55 @@ public class LevelChunk extends ChunkAccess { } } this.setNeighbourLoaded(0, 0, this); @@ -16894,11 +19457,10 @@ index 09999a3f523ce6d652799215d3418284a69042c1..41754f6c8162df07e2b22f4ffcacd8b6 org.bukkit.Server server = this.level.getCraftServer(); - this.level.getChunkSource().addLoadedChunk(this); // Paper + // Paper - rewrite chunk system - move into separate callback -+ ((ServerLevel)this.level).getChunkSource().chunkMap.playerChunkManager.onChunkLoad(this.chunkPos.x, this.chunkPos.z); // Paper - rewrite player chunk management if (server != null) { /* * If it's a new world, the first few chunks are generated inside -@@ -690,6 +790,7 @@ public class LevelChunk extends ChunkAccess { +@@ -690,6 +752,7 @@ public class LevelChunk extends ChunkAccess { */ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration)); @@ -16906,7 +19468,7 @@ index 09999a3f523ce6d652799215d3418284a69042c1..41754f6c8162df07e2b22f4ffcacd8b6 if (this.needsDecoration) { try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper -@@ -718,9 +819,11 @@ public class LevelChunk extends ChunkAccess { +@@ -718,9 +781,11 @@ public class LevelChunk extends ChunkAccess { } public void unloadCallback() { @@ -16919,7 +19481,7 @@ index 09999a3f523ce6d652799215d3418284a69042c1..41754f6c8162df07e2b22f4ffcacd8b6 server.getPluginManager().callEvent(unloadEvent); // note: saving can be prevented, but not forced if no saving is actually required this.mustNotSave = !unloadEvent.isSaveChunk(); -@@ -742,9 +845,26 @@ public class LevelChunk extends ChunkAccess { +@@ -742,9 +807,26 @@ public class LevelChunk extends ChunkAccess { // Paper end } @@ -16947,7 +19509,7 @@ index 09999a3f523ce6d652799215d3418284a69042c1..41754f6c8162df07e2b22f4ffcacd8b6 } // CraftBukkit end -@@ -813,7 +933,9 @@ public class LevelChunk extends ChunkAccess { +@@ -813,7 +895,9 @@ public class LevelChunk extends ChunkAccess { return this.blockEntities; } @@ -16957,19 +19519,26 @@ index 09999a3f523ce6d652799215d3418284a69042c1..41754f6c8162df07e2b22f4ffcacd8b6 ChunkPos chunkcoordintpair = this.getPos(); for (int i = 0; i < this.postProcessing.length; ++i) { -@@ -851,6 +973,11 @@ public class LevelChunk extends ChunkAccess { +@@ -834,6 +918,7 @@ public class LevelChunk extends ChunkAccess { + BlockState iblockdata1 = Block.updateFromNeighbourShapes(iblockdata, this.level, blockposition); + + this.level.setBlock(blockposition, iblockdata1, 20); ++ if (iblockdata1 != iblockdata) this.level.chunkSource.blockChanged(blockposition); // Paper - replace player chunk loader - notify since we send before processing full updates + } + } + +@@ -851,6 +936,10 @@ public class LevelChunk extends ChunkAccess { this.pendingBlockEntities.clear(); this.upgradeData.upgrade(this); + } finally { // Paper start - replace chunk loader system + this.isPostProcessingDone = true; -+ this.level.getChunkSource().chunkMap.playerChunkManager.onChunkPostProcessing(this.chunkPos.x, this.chunkPos.z); + } + // Paper end - replace chunk loader system } @Nullable -@@ -900,7 +1027,7 @@ public class LevelChunk extends ChunkAccess { +@@ -900,7 +989,7 @@ public class LevelChunk extends ChunkAccess { } public FullChunkStatus getFullStatus() { @@ -16979,10 +19548,10 @@ index 09999a3f523ce6d652799215d3418284a69042c1..41754f6c8162df07e2b22f4ffcacd8b6 public void setFullStatus(Supplier levelTypeProvider) { diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 24892ae367e19038625e243bcdf1bb694632ede5..55da32077d1db81ba197da0be5896da694f4bfa9 100644 +index 24892ae367e19038625e243bcdf1bb694632ede5..a7ee469bb2880a78540b79ae691ea449dfe22ce4 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -94,7 +94,31 @@ public class ChunkSerializer { +@@ -94,7 +94,27 @@ public class ChunkSerializer { public ChunkSerializer() {} @@ -16990,13 +19559,11 @@ index 24892ae367e19038625e243bcdf1bb694632ede5..55da32077d1db81ba197da0be5896da6 + public static final class InProgressChunkHolder { + + public final ProtoChunk protoChunk; -+ public final java.util.ArrayDeque tasks; + + public CompoundTag poiData; + -+ public InProgressChunkHolder(final ProtoChunk protoChunk, final java.util.ArrayDeque tasks) { ++ public InProgressChunkHolder(final ProtoChunk protoChunk) { + this.protoChunk = protoChunk; -+ this.tasks = tasks; + } + } + // Paper end @@ -17004,41 +19571,38 @@ index 24892ae367e19038625e243bcdf1bb694632ede5..55da32077d1db81ba197da0be5896da6 public static ProtoChunk read(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt) { + // Paper start - add variant for async calls + InProgressChunkHolder holder = loadChunk(world, poiStorage, chunkPos, nbt, true); -+ holder.tasks.forEach(Runnable::run); + return holder.protoChunk; + } + + public static InProgressChunkHolder loadChunk(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt, boolean distinguish) { -+ java.util.ArrayDeque tasksToExecuteOnMain = new java.util.ArrayDeque<>(); + // Paper end ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); if (!Objects.equals(chunkPos, chunkcoordintpair1)) { -@@ -160,7 +184,9 @@ public class ChunkSerializer { +@@ -160,7 +180,7 @@ public class ChunkSerializer { achunksection[k] = chunksection; SectionPos sectionposition = SectionPos.of(chunkPos, b0); -+ tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main - poiStorage.checkConsistencyWithBlocks(sectionposition, chunksection); -+ }); // Paper - delay this task since we're executing off-main +- poiStorage.checkConsistencyWithBlocks(sectionposition, chunksection); ++ // Paper - rewrite chunk system - moved to final load stage } boolean flag3 = nbttagcompound1.contains("BlockLight", 7); -@@ -306,7 +332,7 @@ public class ChunkSerializer { +@@ -306,7 +326,7 @@ public class ChunkSerializer { } if (chunkstatus_type == ChunkStatus.ChunkType.LEVELCHUNK) { - return new ImposterProtoChunk((LevelChunk) object1, false); -+ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object1, false), tasksToExecuteOnMain); // Paper - Async chunk loading ++ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object1, false)); // Paper - Async chunk loading } else { ProtoChunk protochunk1 = (ProtoChunk) object1; -@@ -334,9 +360,41 @@ public class ChunkSerializer { +@@ -334,9 +354,41 @@ public class ChunkSerializer { protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound5.getLongArray(s1), ((ChunkAccess) object1).getMinBuildHeight())); } - return protochunk1; -+ return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading ++ return new InProgressChunkHolder(protochunk1); // Paper - Async chunk loading + } + } + @@ -17076,7 +19640,7 @@ index 24892ae367e19038625e243bcdf1bb694632ede5..55da32077d1db81ba197da0be5896da6 private static void logErrors(ChunkPos chunkPos, int y, String message) { ChunkSerializer.LOGGER.error("Recoverable errors when loading section [" + chunkPos.x + ", " + y + ", " + chunkPos.z + "]: " + message); -@@ -353,6 +411,11 @@ public class ChunkSerializer { +@@ -353,6 +405,11 @@ public class ChunkSerializer { // CraftBukkit end public static CompoundTag write(ServerLevel world, ChunkAccess chunk) { @@ -17088,7 +19652,7 @@ index 24892ae367e19038625e243bcdf1bb694632ede5..55da32077d1db81ba197da0be5896da6 // Paper start - rewrite light impl final int minSection = io.papermc.paper.util.WorldUtil.getMinLightSection(world); final int maxSection = io.papermc.paper.util.WorldUtil.getMaxLightSection(world); -@@ -365,7 +428,7 @@ public class ChunkSerializer { +@@ -365,7 +422,7 @@ public class ChunkSerializer { nbttagcompound.putInt("xPos", chunkcoordintpair.x); nbttagcompound.putInt("yPos", chunk.getMinSection()); nbttagcompound.putInt("zPos", chunkcoordintpair.z); @@ -17097,7 +19661,7 @@ index 24892ae367e19038625e243bcdf1bb694632ede5..55da32077d1db81ba197da0be5896da6 nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime()); nbttagcompound.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(chunk.getStatus()).toString()); BlendingData blendingdata = chunk.getBlendingData(); -@@ -465,8 +528,17 @@ public class ChunkSerializer { +@@ -465,8 +522,17 @@ public class ChunkSerializer { nbttagcompound.putBoolean("isLightOn", false); // Paper - set to false but still store, this allows us to detect --eraseCache (as eraseCache _removes_) } @@ -17117,7 +19681,7 @@ index 24892ae367e19038625e243bcdf1bb694632ede5..55da32077d1db81ba197da0be5896da6 CompoundTag nbttagcompound2; -@@ -502,7 +574,14 @@ public class ChunkSerializer { +@@ -502,7 +568,14 @@ public class ChunkSerializer { nbttagcompound.put("CarvingMasks", nbttagcompound2); } @@ -17462,20 +20026,50 @@ index d9daf07132c46548964a75588b69d7a74680e917..e68205fe7169c7c5b7c6fdada2ee97d8 } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index b9b50c56e79297bb824a92355f437a5d4d7e6760..18ef7025f7f4dc2a4aff85ca65ff5a2d35a1ef06 100644 +index b9b50c56e79297bb824a92355f437a5d4d7e6760..fe8bb0037bb7f317fc32ac34461f4eb3a1f397f2 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -24,16 +24,37 @@ public class RegionFileStorage implements AutoCloseable { +@@ -24,30 +24,98 @@ public class RegionFileStorage implements AutoCloseable { private final Path folder; private final boolean sync; - RegionFileStorage(Path directory, boolean dsync) { ++ // Paper start - cache regionfile does not exist state ++ static final int MAX_NON_EXISTING_CACHE = 1024 * 64; ++ private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet(); ++ private synchronized boolean doesRegionFilePossiblyExist(long position) { ++ if (this.nonExistingRegionFiles.contains(position)) { ++ this.nonExistingRegionFiles.addAndMoveToFirst(position); ++ return false; ++ } ++ return true; ++ } ++ ++ private synchronized void createRegionFile(long position) { ++ this.nonExistingRegionFiles.remove(position); ++ } ++ ++ private synchronized void markNonExisting(long position) { ++ if (this.nonExistingRegionFiles.addAndMoveToFirst(position)) { ++ while (this.nonExistingRegionFiles.size() >= MAX_NON_EXISTING_CACHE) { ++ this.nonExistingRegionFiles.removeLastLong(); ++ } ++ } ++ } ++ ++ public synchronized boolean doesRegionFileNotExistNoIO(ChunkPos pos) { ++ long key = ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()); ++ return !this.doesRegionFilePossiblyExist(key); ++ } ++ // Paper end - cache regionfile does not exist state ++ + protected RegionFileStorage(Path directory, boolean dsync) { // Paper - protected constructor this.folder = directory; this.sync = dsync; } - private RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit +- long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); + // Paper start + public synchronized RegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) { + return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ())); @@ -17492,7 +20086,7 @@ index b9b50c56e79297bb824a92355f437a5d4d7e6760..18ef7025f7f4dc2a4aff85ca65ff5a2d + } + public synchronized RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException { + // Paper end - long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); ++ long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); final long regionPos = i; // Paper - OBFHELPER RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i); if (regionfile != null) { @@ -17504,8 +20098,29 @@ index b9b50c56e79297bb824a92355f437a5d4d7e6760..18ef7025f7f4dc2a4aff85ca65ff5a2d + // Paper end return regionfile; } else { ++ // Paper start - cache regionfile does not exist state ++ if (existingOnly && !this.doesRegionFilePossiblyExist(regionPos)) { ++ return null; ++ } ++ // Paper end - cache regionfile does not exist state if (this.regionCache.size() >= 256) { -@@ -48,6 +69,12 @@ public class RegionFileStorage implements AutoCloseable { + ((RegionFile) this.regionCache.removeLast()).close(); + } + +- FileUtil.createDirectoriesSafe(this.folder); ++ // Paper - only create directory if not existing only - moved down + Path path = this.folder; + int j = chunkcoordintpair.getRegionX(); + Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); +- if (existingOnly && !java.nio.file.Files.exists(path1)) return null; // CraftBukkit ++ if (existingOnly && !java.nio.file.Files.exists(path1)) { // Paper start - cache regionfile does not exist state ++ this.markNonExisting(regionPos); ++ return null; // CraftBukkit ++ } else { ++ this.createRegionFile(regionPos); ++ } ++ // Paper end - cache regionfile does not exist state ++ FileUtil.createDirectoriesSafe(this.folder); // Paper - only create directory if not existing only - moved from above RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync); this.regionCache.putAndMoveToFirst(i, regionfile1); @@ -17518,7 +20133,7 @@ index b9b50c56e79297bb824a92355f437a5d4d7e6760..18ef7025f7f4dc2a4aff85ca65ff5a2d return regionfile1; } } -@@ -55,11 +82,12 @@ public class RegionFileStorage implements AutoCloseable { +@@ -55,11 +123,12 @@ public class RegionFileStorage implements AutoCloseable { @Nullable public CompoundTag read(ChunkPos pos) throws IOException { // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing @@ -17532,7 +20147,7 @@ index b9b50c56e79297bb824a92355f437a5d4d7e6760..18ef7025f7f4dc2a4aff85ca65ff5a2d DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos); CompoundTag nbttagcompound; -@@ -96,6 +124,9 @@ public class RegionFileStorage implements AutoCloseable { +@@ -96,6 +165,9 @@ public class RegionFileStorage implements AutoCloseable { } return nbttagcompound; @@ -17542,7 +20157,7 @@ index b9b50c56e79297bb824a92355f437a5d4d7e6760..18ef7025f7f4dc2a4aff85ca65ff5a2d } public void scanChunk(ChunkPos chunkPos, StreamTagVisitor scanner) throws IOException { -@@ -130,7 +161,12 @@ public class RegionFileStorage implements AutoCloseable { +@@ -130,7 +202,12 @@ public class RegionFileStorage implements AutoCloseable { } protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { @@ -17556,7 +20171,7 @@ index b9b50c56e79297bb824a92355f437a5d4d7e6760..18ef7025f7f4dc2a4aff85ca65ff5a2d if (nbt == null) { regionfile.clear(pos); -@@ -156,9 +192,12 @@ public class RegionFileStorage implements AutoCloseable { +@@ -156,9 +233,12 @@ public class RegionFileStorage implements AutoCloseable { } } @@ -17570,7 +20185,7 @@ index b9b50c56e79297bb824a92355f437a5d4d7e6760..18ef7025f7f4dc2a4aff85ca65ff5a2d ExceptionCollector exceptionsuppressor = new ExceptionCollector<>(); ObjectIterator objectiterator = this.regionCache.values().iterator(); -@@ -175,7 +214,7 @@ public class RegionFileStorage implements AutoCloseable { +@@ -175,7 +255,7 @@ public class RegionFileStorage implements AutoCloseable { exceptionsuppressor.throwIfPresent(); } @@ -17944,7 +20559,7 @@ index 7912cf0e4cab7d6c99106d43b2cdc4f4e80aebac..0a4b2529034b85609b2f8d3f3f633e8f // Paper start diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 1440b6b8b71ece71b076601752b06bdcff45542f..49623627555cb2b18ea8f7e17d0f6c1db54c0be4 100644 +index 1440b6b8b71ece71b076601752b06bdcff45542f..7c4d43096031a3c93d5f835922b19d5643005128 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -323,10 +323,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -18011,13 +20626,13 @@ index 1440b6b8b71ece71b076601752b06bdcff45542f..49623627555cb2b18ea8f7e17d0f6c1d @Override public int getViewDistance() { - return world.spigotConfig.viewDistance; -+ return getHandle().getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance(); // Paper - replace old player chunk management ++ return this.getHandle().playerChunkLoader.getAPIViewDistance(); // Paper - replace player chunk loader } @Override public int getSimulationDistance() { - return world.spigotConfig.simulationDistance; -+ return getHandle().getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance(); // Paper - replace old player chunk management ++ return this.getHandle().playerChunkLoader.getAPITickDistance(); // Paper - replace player chunk loader } // Spigot end + // Paper start - view distance api @@ -18051,66 +20666,44 @@ index 1440b6b8b71ece71b076601752b06bdcff45542f..49623627555cb2b18ea8f7e17d0f6c1d + + @Override + public int getSendViewDistance() { -+ return getHandle().getChunkSource().chunkMap.playerChunkManager.getTargetSendDistance(); ++ return this.getHandle().playerChunkLoader.getAPISendViewDistance(); // Paper - replace player chunk loader + } + + @Override + public void setSendViewDistance(int viewDistance) { -+ getHandle().getChunkSource().chunkMap.playerChunkManager.setSendDistance(viewDistance); ++ this.getHandle().chunkSource.chunkMap.setSendViewDistance(viewDistance); // Paper - replace player chunk loader + } + // Paper end - view distance api // Spigot start private final org.bukkit.World.Spigot spigot = new org.bukkit.World.Spigot() diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 5afdada0d56c2f9af431ea6485faa277229befa9..2f35f954eb2dcdc2de54b54c47c139908438e0f0 100644 +index 5afdada0d56c2f9af431ea6485faa277229befa9..976eadd8200b2f4811d57b3c7fbd68cff1333924 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -184,6 +184,81 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -184,6 +184,48 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.firstPlayed = System.currentTimeMillis(); } + // Paper start - implement view distances + @Override + public int getViewDistance() { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ return chunkMap.playerChunkManager.getTargetNoTickViewDistance(); -+ } -+ return data.getTargetNoTickViewDistance(); ++ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPIViewDistance(this); + } + + @Override + public void setViewDistance(int viewDistance) { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ throw new IllegalStateException("Player is not attached to world"); -+ } -+ -+ data.setTargetNoTickViewDistance(viewDistance); ++ this.getHandle().setLoadViewDistance(viewDistance < 0 ? viewDistance : viewDistance + 1); + } + + @Override + public int getSimulationDistance() { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ return chunkMap.playerChunkManager.getTargetTickViewDistance(); -+ } -+ return data.getTargetTickViewDistance(); ++ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPITickViewDistance(this); + } + + @Override + public void setSimulationDistance(int simulationDistance) { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ throw new IllegalStateException("Player is not attached to world"); -+ } -+ -+ data.setTargetTickViewDistance(simulationDistance); ++ this.getHandle().setTickViewDistance(simulationDistance); + } + + @Override @@ -18125,23 +20718,12 @@ index 5afdada0d56c2f9af431ea6485faa277229befa9..2f35f954eb2dcdc2de54b54c47c13990 + + @Override + public int getSendViewDistance() { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ return chunkMap.playerChunkManager.getTargetSendDistance(); -+ } -+ return data.getTargetSendViewDistance(); ++ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPISendViewDistance(this); + } + + @Override + public void setSendViewDistance(int viewDistance) { -+ net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -+ io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -+ if (data == null) { -+ throw new IllegalStateException("Player is not attached to world"); -+ } -+ -+ data.setTargetSendViewDistance(viewDistance); ++ this.getHandle().setSendViewDistance(viewDistance); + } + // Paper end - implement view distances + diff --git a/patches/server/0022-Configurable-baby-zombie-movement-speed.patch b/patches/server/0021-Configurable-baby-zombie-movement-speed.patch similarity index 100% rename from patches/server/0022-Configurable-baby-zombie-movement-speed.patch rename to patches/server/0021-Configurable-baby-zombie-movement-speed.patch diff --git a/patches/server/0021-New-player-chunk-loader-system.patch b/patches/server/0021-New-player-chunk-loader-system.patch deleted file mode 100644 index 7665e63540..0000000000 --- a/patches/server/0021-New-player-chunk-loader-system.patch +++ /dev/null @@ -1,2367 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Wed, 1 Feb 2023 21:06:31 -0800 -Subject: [PATCH] New player chunk loader system - - -diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java -index 43380d5e3a40b64bebdf3c0e7c48eca8998c8ac0..1080e1f67afe5574baca0df50cdb1d029a7a586a 100644 ---- a/src/main/java/co/aikar/timings/TimingsExport.java -+++ b/src/main/java/co/aikar/timings/TimingsExport.java -@@ -164,9 +164,9 @@ public class TimingsExport extends Thread { - return pair(rule, world.getWorld().getGameRuleValue(rule)); - })), - // Paper start - replace chunk loader system -- pair("ticking-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance()), -- pair("no-ticking-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance()), -- pair("sending-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetSendDistance()) -+ pair("ticking-distance", world.getWorld().getSimulationDistance()), -+ pair("no-ticking-distance", world.getWorld().getViewDistance()), -+ pair("sending-distance", world.getWorld().getSendViewDistance()) - // Paper end - replace chunk loader system - )); - })); -diff --git a/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java -index e77972c4c264100ffdd824bfa2dac58dbbc6d678..562630db2cf5f923bf5b611b828a365e6d60fefb 100644 ---- a/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java -+++ b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java -@@ -41,12 +41,7 @@ public final class PlayerChunkLoader { - } - - public static int getTickViewDistance(final ServerPlayer player) { -- final ServerLevel level = (ServerLevel)player.level; -- final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player); -- if (data == null) { -- return level.chunkSource.chunkMap.playerChunkManager.getTargetTickViewDistance(); -- } -- return data.getTargetTickViewDistance(); -+ throw new UnsupportedOperationException(); - } - - public static int getLoadViewDistance(final Player player) { -@@ -54,12 +49,7 @@ public final class PlayerChunkLoader { - } - - public static int getLoadViewDistance(final ServerPlayer player) { -- final ServerLevel level = (ServerLevel)player.level; -- final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player); -- if (data == null) { -- return level.chunkSource.chunkMap.playerChunkManager.getLoadDistance(); -- } -- return data.getLoadDistance(); -+ throw new UnsupportedOperationException(); - } - - public static int getSendViewDistance(final Player player) { -@@ -67,12 +57,7 @@ public final class PlayerChunkLoader { - } - - public static int getSendViewDistance(final ServerPlayer player) { -- final ServerLevel level = (ServerLevel)player.level; -- final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player); -- if (data == null) { -- return level.chunkSource.chunkMap.playerChunkManager.getTargetSendDistance(); -- } -- return data.getTargetSendViewDistance(); -+ throw new UnsupportedOperationException(); - } - - protected final ChunkMap chunkMap; -@@ -872,7 +857,7 @@ public final class PlayerChunkLoader { - - public void sendChunk(final int chunkX, final int chunkZ, final Runnable onChunkSend) { - if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -- this.player.getLevel().getChunkSource().chunkMap.updateChunkTracking(this.player, -+ ((ServerLevel)this.player.level()).getChunkSource().chunkMap.updateChunkTracking(this.player, - new ChunkPos(chunkX, chunkZ), new MutableObject<>(), false, true); // unloaded, loaded - this.player.connection.connection.execute(onChunkSend); - } else { -@@ -882,7 +867,7 @@ public final class PlayerChunkLoader { - - public void unloadChunk(final int chunkX, final int chunkZ) { - if (this.sentChunks.remove(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -- this.player.getLevel().getChunkSource().chunkMap.updateChunkTracking(this.player, -+ ((ServerLevel)this.player.level()).getChunkSource().chunkMap.updateChunkTracking(this.player, - new ChunkPos(chunkX, chunkZ), null, true, false); // unloaded, loaded - } - } -diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java -index 0dc94dec1317b3f86d38074c6cbe41ab828cab1d..97edd4e8d3524c839a1765b6515deacae112ff4b 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java -+++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java -@@ -119,15 +119,15 @@ public final class ChunkSystem { - } - - public static int getSendViewDistance(final ServerPlayer player) { -- return io.papermc.paper.chunk.PlayerChunkLoader.getSendViewDistance(player); -+ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPISendViewDistance(player); - } - - public static int getLoadViewDistance(final ServerPlayer player) { -- return io.papermc.paper.chunk.PlayerChunkLoader.getLoadViewDistance(player); -+ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getLoadViewDistance(player); - } - - public static int getTickViewDistance(final ServerPlayer player) { -- return io.papermc.paper.chunk.PlayerChunkLoader.getTickViewDistance(player); -+ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPITickViewDistance(player); - } - - private ChunkSystem() { -diff --git a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cf7610b3396d03bf79a899d5d9cfc6debb5b90be ---- /dev/null -+++ b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -@@ -0,0 +1,1332 @@ -+package io.papermc.paper.chunk.system; -+ -+import ca.spottedleaf.concurrentutil.collection.SRSWLinkedQueue; -+import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; -+import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; -+import io.papermc.paper.chunk.system.io.RegionFileIOThread; -+import io.papermc.paper.chunk.system.scheduling.ChunkHolderManager; -+import io.papermc.paper.configuration.GlobalConfiguration; -+import io.papermc.paper.util.CoordinateUtils; -+import io.papermc.paper.util.IntegerUtil; -+import io.papermc.paper.util.TickThread; -+import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -+import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; -+import it.unimi.dsi.fastutil.longs.LongArrayList; -+import it.unimi.dsi.fastutil.longs.LongComparator; -+import it.unimi.dsi.fastutil.longs.LongHeapPriorityQueue; -+import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -+import net.minecraft.network.protocol.Packet; -+import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket; -+import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket; -+import net.minecraft.network.protocol.game.ClientboundSetSimulationDistancePacket; -+import net.minecraft.server.level.ChunkMap; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.level.TicketType; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.GameRules; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; -+import net.minecraft.world.level.chunk.LevelChunk; -+import net.minecraft.world.level.levelgen.BelowZeroRetrogen; -+import org.apache.commons.lang3.mutable.MutableObject; -+import org.bukkit.craftbukkit.entity.CraftPlayer; -+import org.bukkit.entity.Player; -+import java.lang.invoke.VarHandle; -+import java.util.ArrayDeque; -+import java.util.concurrent.TimeUnit; -+import java.util.concurrent.atomic.AtomicLong; -+ -+public class RegionizedPlayerChunkLoader { -+ -+ public static final TicketType REGION_PLAYER_TICKET = TicketType.create("region_player_ticket", Long::compareTo); -+ -+ public static final int MIN_VIEW_DISTANCE = 2; -+ public static final int MAX_VIEW_DISTANCE = 32; -+ -+ public static final int TICK_TICKET_LEVEL = 31; -+ public static final int GENERATED_TICKET_LEVEL = 33 + ChunkStatus.getDistance(ChunkStatus.FULL); -+ public static final int LOADED_TICKET_LEVEL = 33 + ChunkStatus.getDistance(ChunkStatus.EMPTY); -+ -+ public static final record ViewDistances( -+ int tickViewDistance, -+ int loadViewDistance, -+ int sendViewDistance -+ ) { -+ public ViewDistances setTickViewDistance(final int distance) { -+ return new ViewDistances(distance, this.loadViewDistance, this.sendViewDistance); -+ } -+ -+ public ViewDistances setLoadViewDistance(final int distance) { -+ return new ViewDistances(this.tickViewDistance, distance, this.sendViewDistance); -+ } -+ -+ -+ public ViewDistances setSendViewDistance(final int distance) { -+ return new ViewDistances(this.tickViewDistance, this.loadViewDistance, distance); -+ } -+ } -+ -+ public static int getAPITickViewDistance(final Player player) { -+ return getAPITickViewDistance(((CraftPlayer)player).getHandle()); -+ } -+ -+ public static int getAPITickViewDistance(final ServerPlayer player) { -+ final ServerLevel level = (ServerLevel)player.level(); -+ final PlayerChunkLoaderData data = player.chunkLoader; -+ if (data == null) { -+ return level.playerChunkLoader.getAPITickDistance(); -+ } -+ return data.lastTickDistance; -+ } -+ -+ public static int getAPIViewDistance(final Player player) { -+ return getAPIViewDistance(((CraftPlayer)player).getHandle()); -+ } -+ -+ public static int getAPIViewDistance(final ServerPlayer player) { -+ final ServerLevel level = (ServerLevel)player.level(); -+ final PlayerChunkLoaderData data = player.chunkLoader; -+ if (data == null) { -+ return level.playerChunkLoader.getAPIViewDistance(); -+ } -+ // view distance = load distance + 1 -+ return data.lastLoadDistance - 1; -+ } -+ -+ public static int getLoadViewDistance(final ServerPlayer player) { -+ final ServerLevel level = (ServerLevel)player.level(); -+ final PlayerChunkLoaderData data = player.chunkLoader; -+ if (data == null) { -+ return level.playerChunkLoader.getAPIViewDistance(); -+ } -+ // view distance = load distance + 1 -+ return data.lastLoadDistance - 1; -+ } -+ -+ public static int getAPISendViewDistance(final Player player) { -+ return getAPISendViewDistance(((CraftPlayer)player).getHandle()); -+ } -+ -+ public static int getAPISendViewDistance(final ServerPlayer player) { -+ final ServerLevel level = (ServerLevel)player.level(); -+ final PlayerChunkLoaderData data = player.chunkLoader; -+ if (data == null) { -+ return level.playerChunkLoader.getAPISendViewDistance(); -+ } -+ return data.lastSendDistance; -+ } -+ -+ private final ServerLevel world; -+ -+ public RegionizedPlayerChunkLoader(final ServerLevel world) { -+ this.world = world; -+ } -+ -+ public void addPlayer(final ServerPlayer player) { -+ TickThread.ensureTickThread(player, "Cannot add player to player chunk loader async"); -+ if (!player.isRealPlayer) { -+ return; -+ } -+ -+ if (player.chunkLoader != null) { -+ throw new IllegalStateException("Player is already added to player chunk loader"); -+ } -+ -+ final PlayerChunkLoaderData loader = new PlayerChunkLoaderData(this.world, player); -+ -+ player.chunkLoader = loader; -+ loader.add(); -+ } -+ -+ public void updatePlayer(final ServerPlayer player) { -+ final PlayerChunkLoaderData loader = player.chunkLoader; -+ if (loader != null) { -+ loader.update(); -+ } -+ } -+ -+ public void removePlayer(final ServerPlayer player) { -+ TickThread.ensureTickThread(player, "Cannot remove player from player chunk loader async"); -+ if (!player.isRealPlayer) { -+ return; -+ } -+ -+ final PlayerChunkLoaderData loader = player.chunkLoader; -+ -+ if (loader == null) { -+ throw new IllegalStateException("Player is already removed from player chunk loader"); -+ } -+ -+ loader.remove(); -+ player.chunkLoader = null; -+ } -+ -+ public void setSendDistance(final int distance) { -+ this.world.setSendViewDistance(distance); -+ } -+ -+ public void setLoadDistance(final int distance) { -+ this.world.setLoadViewDistance(distance); -+ } -+ -+ public void setTickDistance(final int distance) { -+ this.world.setTickViewDistance(distance); -+ } -+ -+ // Note: follow the player chunk loader so everything stays consistent... -+ public int getAPITickDistance() { -+ final ViewDistances distances = this.world.getViewDistances(); -+ final int tickViewDistance = PlayerChunkLoaderData.getTickDistance(-1, distances.tickViewDistance); -+ return tickViewDistance; -+ } -+ -+ public int getAPIViewDistance() { -+ final ViewDistances distances = this.world.getViewDistances(); -+ final int tickViewDistance = PlayerChunkLoaderData.getTickDistance(-1, distances.tickViewDistance); -+ final int loadDistance = PlayerChunkLoaderData.getLoadViewDistance(tickViewDistance, -1, distances.loadViewDistance); -+ -+ // loadDistance = api view distance + 1 -+ return loadDistance - 1; -+ } -+ -+ public int getAPISendViewDistance() { -+ final ViewDistances distances = this.world.getViewDistances(); -+ final int tickViewDistance = PlayerChunkLoaderData.getTickDistance(-1, distances.tickViewDistance); -+ final int loadDistance = PlayerChunkLoaderData.getLoadViewDistance(tickViewDistance, -1, distances.loadViewDistance); -+ final int sendViewDistance = PlayerChunkLoaderData.getSendViewDistance( -+ loadDistance, -1, -1, distances.sendViewDistance -+ ); -+ -+ return sendViewDistance; -+ } -+ -+ public boolean isChunkSent(final ServerPlayer player, final int chunkX, final int chunkZ, final boolean borderOnly) { -+ return borderOnly ? this.isChunkSentBorderOnly(player, chunkX, chunkZ) : this.isChunkSent(player, chunkX, chunkZ); -+ } -+ -+ public boolean isChunkSent(final ServerPlayer player, final int chunkX, final int chunkZ) { -+ final PlayerChunkLoaderData loader = player.chunkLoader; -+ if (loader == null) { -+ return false; -+ } -+ -+ return loader.sentChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ } -+ -+ public boolean isChunkSentBorderOnly(final ServerPlayer player, final int chunkX, final int chunkZ) { -+ final PlayerChunkLoaderData loader = player.chunkLoader; -+ if (loader == null) { -+ return false; -+ } -+ -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ if (!loader.sentChunks.contains(CoordinateUtils.getChunkKey(dx + chunkX, dz + chunkZ))) { -+ return true; -+ } -+ } -+ } -+ -+ return false; -+ } -+ -+ public void tick() { -+ TickThread.ensureTickThread("Cannot tick player chunk loader async"); -+ long currTime = System.nanoTime(); -+ for (final ServerPlayer player : new java.util.ArrayList<>(this.world.players())) { -+ final PlayerChunkLoaderData loader = player.chunkLoader; -+ if (loader == null || loader.world != this.world) { -+ // not our problem anymore -+ continue; -+ } -+ loader.update(); // can't invoke plugin logic -+ loader.updateQueues(currTime); -+ } -+ } -+ -+ private static long[] generateBFSOrder(final int radius) { -+ final LongArrayList chunks = new LongArrayList(); -+ final LongArrayFIFOQueue queue = new LongArrayFIFOQueue(); -+ final LongOpenHashSet seen = new LongOpenHashSet(); -+ -+ seen.add(CoordinateUtils.getChunkKey(0, 0)); -+ queue.enqueue(CoordinateUtils.getChunkKey(0, 0)); -+ while (!queue.isEmpty()) { -+ final long chunk = queue.dequeueLong(); -+ final int chunkX = CoordinateUtils.getChunkX(chunk); -+ final int chunkZ = CoordinateUtils.getChunkZ(chunk); -+ -+ // important that the addition to the list is here, rather than when enqueueing neighbours -+ // ensures the order is actually kept -+ chunks.add(chunk); -+ -+ // -x -+ final long n1 = CoordinateUtils.getChunkKey(chunkX - 1, chunkZ); -+ // -z -+ final long n2 = CoordinateUtils.getChunkKey(chunkX, chunkZ - 1); -+ // +x -+ final long n3 = CoordinateUtils.getChunkKey(chunkX + 1, chunkZ); -+ // +z -+ final long n4 = CoordinateUtils.getChunkKey(chunkX, chunkZ + 1); -+ -+ final long[] list = new long[] {n1, n2, n3, n4}; -+ -+ for (final long neighbour : list) { -+ final int neighbourX = CoordinateUtils.getChunkX(neighbour); -+ final int neighbourZ = CoordinateUtils.getChunkZ(neighbour); -+ if (Math.max(Math.abs(neighbourX), Math.abs(neighbourZ)) > radius) { -+ // don't enqueue out of range -+ continue; -+ } -+ if (!seen.add(neighbour)) { -+ continue; -+ } -+ queue.enqueue(neighbour); -+ } -+ } -+ -+ return chunks.toLongArray(); -+ } -+ -+ public static final class PlayerChunkLoaderData { -+ -+ private static final AtomicLong ID_GENERATOR = new AtomicLong(); -+ private final long id = ID_GENERATOR.incrementAndGet(); -+ private final Long idBoxed = Long.valueOf(this.id); -+ -+ // expected that this list returns for a given radius, the set of chunks ordered -+ // by manhattan distance -+ private static final long[][] SEARCH_RADIUS_ITERATION_LIST = new long[65][]; -+ static { -+ for (int i = 0; i < SEARCH_RADIUS_ITERATION_LIST.length; ++i) { -+ // a BFS around -x, -z, +x, +z will give increasing manhatten distance -+ SEARCH_RADIUS_ITERATION_LIST[i] = generateBFSOrder(i); -+ } -+ } -+ -+ private static final long MAX_RATE = 10_000L; -+ -+ private final ServerPlayer player; -+ private final ServerLevel world; -+ -+ private int lastChunkX = Integer.MIN_VALUE; -+ private int lastChunkZ = Integer.MIN_VALUE; -+ -+ private int lastSendDistance = Integer.MIN_VALUE; -+ private int lastLoadDistance = Integer.MIN_VALUE; -+ private int lastTickDistance = Integer.MIN_VALUE; -+ -+ private int lastSentChunkCenterX = Integer.MIN_VALUE; -+ private int lastSentChunkCenterZ = Integer.MIN_VALUE; -+ -+ private int lastSentChunkRadius = Integer.MIN_VALUE; -+ private int lastSentSimulationDistance = Integer.MIN_VALUE; -+ -+ private boolean canGenerateChunks = true; -+ -+ private final ArrayDeque> delayedTicketOps = new ArrayDeque<>(); -+ private final LongOpenHashSet sentChunks = new LongOpenHashSet(); -+ -+ private static final byte CHUNK_TICKET_STAGE_NONE = 0; -+ private static final byte CHUNK_TICKET_STAGE_LOADING = 1; -+ private static final byte CHUNK_TICKET_STAGE_LOADED = 2; -+ private static final byte CHUNK_TICKET_STAGE_GENERATING = 3; -+ private static final byte CHUNK_TICKET_STAGE_GENERATED = 4; -+ private static final byte CHUNK_TICKET_STAGE_TICK = 5; -+ private static final int[] TICKET_STAGE_TO_LEVEL = new int[] { -+ ChunkHolderManager.MAX_TICKET_LEVEL + 1, -+ LOADED_TICKET_LEVEL, -+ LOADED_TICKET_LEVEL, -+ GENERATED_TICKET_LEVEL, -+ GENERATED_TICKET_LEVEL, -+ TICK_TICKET_LEVEL -+ }; -+ private final Long2ByteOpenHashMap chunkTicketStage = new Long2ByteOpenHashMap(); -+ { -+ this.chunkTicketStage.defaultReturnValue(CHUNK_TICKET_STAGE_NONE); -+ } -+ -+ // rate limiting -+ private final AllocatingRateLimiter chunkSendLimiter = new AllocatingRateLimiter(); -+ private final AllocatingRateLimiter chunkLoadTicketLimiter = new AllocatingRateLimiter(); -+ private final AllocatingRateLimiter chunkGenerateTicketLimiter = new AllocatingRateLimiter(); -+ -+ // queues -+ private final LongComparator CLOSEST_MANHATTAN_DIST = (final long c1, final long c2) -> { -+ final int c1x = CoordinateUtils.getChunkX(c1); -+ final int c1z = CoordinateUtils.getChunkZ(c1); -+ -+ final int c2x = CoordinateUtils.getChunkX(c2); -+ final int c2z = CoordinateUtils.getChunkZ(c2); -+ -+ final int centerX = PlayerChunkLoaderData.this.lastChunkX; -+ final int centerZ = PlayerChunkLoaderData.this.lastChunkZ; -+ -+ return Integer.compare( -+ Math.abs(c1x - centerX) + Math.abs(c1z - centerZ), -+ Math.abs(c2x - centerX) + Math.abs(c2z - centerZ) -+ ); -+ }; -+ private final LongHeapPriorityQueue sendQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); -+ private final LongHeapPriorityQueue tickingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); -+ private final LongHeapPriorityQueue generatingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); -+ private final LongHeapPriorityQueue genQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); -+ private final LongHeapPriorityQueue loadingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); -+ private final LongHeapPriorityQueue loadQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); -+ -+ private volatile boolean removed; -+ -+ public PlayerChunkLoaderData(final ServerLevel world, final ServerPlayer player) { -+ this.world = world; -+ this.player = player; -+ } -+ -+ private void flushDelayedTicketOps() { -+ if (this.delayedTicketOps.isEmpty()) { -+ return; -+ } -+ this.world.chunkTaskScheduler.chunkHolderManager.pushDelayedTicketUpdates(this.delayedTicketOps); -+ this.delayedTicketOps.clear(); -+ this.world.chunkTaskScheduler.chunkHolderManager.tryDrainTicketUpdates(); -+ } -+ -+ private void pushDelayedTicketOp(final ChunkHolderManager.TicketOperation op) { -+ this.delayedTicketOps.addLast(op); -+ } -+ -+ private void sendChunk(final int chunkX, final int chunkZ) { -+ if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -+ this.world.getChunkSource().chunkMap.updateChunkTracking(this.player, -+ new ChunkPos(chunkX, chunkZ), new MutableObject<>(), false, true); // unloaded, loaded -+ return; -+ } -+ throw new IllegalStateException(); -+ } -+ -+ private void sendUnloadChunk(final int chunkX, final int chunkZ) { -+ if (!this.sentChunks.remove(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -+ return; -+ } -+ this.sendUnloadChunkRaw(chunkX, chunkZ); -+ } -+ -+ private void sendUnloadChunkRaw(final int chunkX, final int chunkZ) { -+ this.player.serverLevel().getChunkSource().chunkMap.updateChunkTracking(this.player, -+ new ChunkPos(chunkX, chunkZ), null, true, false); // unloaded, loaded -+ } -+ -+ private final SingleUserAreaMap broadcastMap = new SingleUserAreaMap<>(this) { -+ @Override -+ protected void addCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { -+ // do nothing, we only care about remove -+ } -+ -+ @Override -+ protected void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { -+ parameter.sendUnloadChunk(chunkX, chunkZ); -+ } -+ }; -+ private final SingleUserAreaMap loadTicketCleanup = new SingleUserAreaMap<>(this) { -+ @Override -+ protected void addCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { -+ // do nothing, we only care about remove -+ } -+ -+ @Override -+ protected void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { -+ final long chunk = CoordinateUtils.getChunkKey(chunkX, chunkZ); -+ final byte ticketStage = parameter.chunkTicketStage.remove(chunk); -+ final int level = TICKET_STAGE_TO_LEVEL[ticketStage]; -+ if (level > ChunkHolderManager.MAX_TICKET_LEVEL) { -+ return; -+ } -+ -+ parameter.pushDelayedTicketOp(ChunkHolderManager.TicketOperation.addAndRemove( -+ chunk, -+ TicketType.UNKNOWN, level, new ChunkPos(chunkX, chunkZ), -+ REGION_PLAYER_TICKET, level, parameter.idBoxed -+ )); -+ } -+ }; -+ private final SingleUserAreaMap tickMap = new SingleUserAreaMap<>(this) { -+ @Override -+ protected void addCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { -+ // do nothing, we will detect ticking chunks when we try to load them -+ } -+ -+ @Override -+ protected void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { -+ final long chunk = CoordinateUtils.getChunkKey(chunkX, chunkZ); -+ // note: by the time this is called, the tick cleanup should have ran - so, if the chunk is at -+ // the tick stage it was deemed in range for loading. Thus, we need to move it to generated -+ if (!parameter.chunkTicketStage.replace(chunk, CHUNK_TICKET_STAGE_TICK, CHUNK_TICKET_STAGE_GENERATED)) { -+ return; -+ } -+ -+ // Since we are possibly downgrading the ticket level, we add an unknown ticket so that -+ // the level is kept until tick(). -+ parameter.pushDelayedTicketOp(ChunkHolderManager.TicketOperation.addAndRemove( -+ chunk, -+ TicketType.UNKNOWN, TICK_TICKET_LEVEL, new ChunkPos(chunkX, chunkZ), -+ REGION_PLAYER_TICKET, TICK_TICKET_LEVEL, parameter.idBoxed -+ )); -+ // keep chunk at new generated level -+ parameter.pushDelayedTicketOp(ChunkHolderManager.TicketOperation.addOp( -+ chunk, -+ REGION_PLAYER_TICKET, GENERATED_TICKET_LEVEL, parameter.idBoxed -+ )); -+ } -+ }; -+ -+ private static boolean wantChunkLoaded(final int centerX, final int centerZ, final int chunkX, final int chunkZ, -+ final int sendRadius) { -+ // expect sendRadius to be = 1 + target viewable radius -+ return ChunkMap.isChunkInRange(chunkX, chunkZ, centerX, centerZ, sendRadius); -+ } -+ -+ private static int getClientViewDistance(final ServerPlayer player) { -+ final Integer vd = player.clientViewDistance; -+ return vd == null ? -1 : Math.max(0, vd.intValue()); -+ } -+ -+ private static int getTickDistance(final int playerTickViewDistance, final int worldTickViewDistance) { -+ return playerTickViewDistance < 0 ? worldTickViewDistance : playerTickViewDistance; -+ } -+ -+ private static int getLoadViewDistance(final int tickViewDistance, final int playerLoadViewDistance, -+ final int worldLoadViewDistance) { -+ return Math.max(tickViewDistance, playerLoadViewDistance < 0 ? worldLoadViewDistance : playerLoadViewDistance); -+ } -+ -+ private static int getSendViewDistance(final int loadViewDistance, final int clientViewDistance, -+ final int playerSendViewDistance, final int worldSendViewDistance) { -+ return Math.min( -+ loadViewDistance, -+ playerSendViewDistance < 0 ? (!GlobalConfiguration.get().chunkLoadingAdvanced.autoConfigSendDistance || clientViewDistance < 0 ? (worldSendViewDistance < 0 ? loadViewDistance : worldSendViewDistance) : clientViewDistance) : playerSendViewDistance -+ ); -+ } -+ -+ private Packet updateClientChunkRadius(final int radius) { -+ this.lastSentChunkRadius = radius; -+ return new ClientboundSetChunkCacheRadiusPacket(radius); -+ } -+ -+ private Packet updateClientSimulationDistance(final int distance) { -+ this.lastSentSimulationDistance = distance; -+ return new ClientboundSetSimulationDistancePacket(distance); -+ } -+ -+ private Packet updateClientChunkCenter(final int chunkX, final int chunkZ) { -+ this.lastSentChunkCenterX = chunkX; -+ this.lastSentChunkCenterZ = chunkZ; -+ return new ClientboundSetChunkCacheCenterPacket(chunkX, chunkZ); -+ } -+ -+ private boolean canPlayerGenerateChunks() { -+ return !this.player.isSpectator() || this.world.getGameRules().getBoolean(GameRules.RULE_SPECTATORSGENERATECHUNKS); -+ } -+ -+ private double getMaxChunkLoadRate() { -+ final double configRate = GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkLoadRate; -+ -+ return configRate < 0.0 || configRate > (double)MAX_RATE ? (double)MAX_RATE : Math.max(1.0, configRate); -+ } -+ -+ private double getMaxChunkGenRate() { -+ final double configRate = GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkGenerateRate; -+ -+ return configRate < 0.0 || configRate > (double)MAX_RATE ? (double)MAX_RATE : Math.max(1.0, configRate); -+ } -+ -+ private double getMaxChunkSendRate() { -+ final double configRate = GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkSendRate; -+ -+ return configRate < 0.0 || configRate > (double)MAX_RATE ? (double)MAX_RATE : Math.max(1.0, configRate); -+ } -+ -+ private long getMaxChunkLoads() { -+ final long radiusChunks = (2L * this.lastLoadDistance + 1L) * (2L * this.lastLoadDistance + 1L); -+ long configLimit = GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkLoads; -+ if (configLimit == 0L) { -+ // by default, only allow 1/5th of the chunks in the view distance to be concurrently active -+ configLimit = Math.max(5L, radiusChunks / 5L); -+ } else if (configLimit < 0L) { -+ configLimit = Integer.MAX_VALUE; -+ } // else: use the value configured -+ configLimit = configLimit - this.loadingQueue.size(); -+ -+ return configLimit; -+ } -+ -+ private long getMaxChunkGenerates() { -+ final long radiusChunks = (2L * this.lastLoadDistance + 1L) * (2L * this.lastLoadDistance + 1L); -+ long configLimit = GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkGenerates; -+ if (configLimit == 0L) { -+ // by default, only allow 1/5th of the chunks in the view distance to be concurrently active -+ configLimit = Math.max(5L, radiusChunks / 5L); -+ } else if (configLimit < 0L) { -+ configLimit = Integer.MAX_VALUE; -+ } // else: use the value configured -+ configLimit = configLimit - this.generatingQueue.size(); -+ -+ return configLimit; -+ } -+ -+ private boolean wantChunkSent(final int chunkX, final int chunkZ) { -+ final int dx = this.lastChunkX - chunkX; -+ final int dz = this.lastChunkZ - chunkZ; -+ return Math.max(Math.abs(dx), Math.abs(dz)) <= this.lastSendDistance && wantChunkLoaded( -+ this.lastChunkX, this.lastChunkZ, chunkX, chunkZ, this.lastSendDistance -+ ); -+ } -+ -+ private boolean wantChunkTicked(final int chunkX, final int chunkZ) { -+ final int dx = this.lastChunkX - chunkX; -+ final int dz = this.lastChunkZ - chunkZ; -+ return Math.max(Math.abs(dx), Math.abs(dz)) <= this.lastTickDistance; -+ } -+ -+ void updateQueues(final long time) { -+ TickThread.ensureTickThread(this.player, "Cannot tick player chunk loader async"); -+ if (this.removed) { -+ throw new IllegalStateException("Ticking removed player chunk loader"); -+ } -+ // update rate limits -+ final double loadRate = this.getMaxChunkLoadRate(); -+ final double genRate = this.getMaxChunkGenRate(); -+ final double sendRate = this.getMaxChunkSendRate(); -+ -+ this.chunkLoadTicketLimiter.tickAllocation(time, loadRate, loadRate); -+ this.chunkGenerateTicketLimiter.tickAllocation(time, genRate, genRate); -+ this.chunkSendLimiter.tickAllocation(time, sendRate, sendRate); -+ -+ // try to progress chunk loads -+ while (!this.loadingQueue.isEmpty()) { -+ final long pendingLoadChunk = this.loadingQueue.firstLong(); -+ final int pendingChunkX = CoordinateUtils.getChunkX(pendingLoadChunk); -+ final int pendingChunkZ = CoordinateUtils.getChunkZ(pendingLoadChunk); -+ final ChunkAccess pending = this.world.chunkSource.getChunkAtImmediately(pendingChunkX, pendingChunkZ); -+ if (pending == null) { -+ // nothing to do here -+ break; -+ } -+ // chunk has loaded, so we can take it out of the queue -+ this.loadingQueue.dequeueLong(); -+ -+ // try to move to generate queue -+ final byte prev = this.chunkTicketStage.put(pendingLoadChunk, CHUNK_TICKET_STAGE_LOADED); -+ if (prev != CHUNK_TICKET_STAGE_LOADING) { -+ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_LOADING + ", not " + prev); -+ } -+ -+ if (this.canGenerateChunks || this.isLoadedChunkGeneratable(pending)) { -+ this.genQueue.enqueue(pendingLoadChunk); -+ } // else: don't want to generate, so just leave it loaded -+ } -+ -+ // try to push more chunk loads -+ final long maxLoads = Math.max(0L, Math.min(MAX_RATE, Math.min(this.loadQueue.size(), this.getMaxChunkLoads()))); -+ final int maxLoadsThisTick = (int)this.chunkLoadTicketLimiter.takeAllocation(time, loadRate, maxLoads); -+ if (maxLoadsThisTick > 0) { -+ final LongArrayList chunks = new LongArrayList(maxLoadsThisTick); -+ for (int i = 0; i < maxLoadsThisTick; ++i) { -+ final long chunk = this.loadQueue.dequeueLong(); -+ final byte prev = this.chunkTicketStage.put(chunk, CHUNK_TICKET_STAGE_LOADING); -+ if (prev != CHUNK_TICKET_STAGE_NONE) { -+ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_NONE + ", not " + prev); -+ } -+ this.pushDelayedTicketOp( -+ ChunkHolderManager.TicketOperation.addOp( -+ chunk, -+ REGION_PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed -+ ) -+ ); -+ chunks.add(chunk); -+ this.loadingQueue.enqueue(chunk); -+ } -+ -+ // here we need to flush tickets, as scheduleChunkLoad requires tickets to be propagated with addTicket = false -+ this.flushDelayedTicketOps(); -+ // we only need to call scheduleChunkLoad because the loaded ticket level is not enough to start the chunk -+ // load - only generate ticket levels start anything, but they start generation... -+ // propagate levels -+ // Note: this CAN call plugin logic, so it is VITAL that our bookkeeping logic is completely done by the time this is invoked -+ this.world.chunkTaskScheduler.chunkHolderManager.processTicketUpdates(); -+ -+ if (this.removed) { -+ // process ticket updates may invoke plugin logic, which may remove this player -+ return; -+ } -+ -+ for (int i = 0; i < maxLoadsThisTick; ++i) { -+ final long queuedLoadChunk = chunks.getLong(i); -+ final int queuedChunkX = CoordinateUtils.getChunkX(queuedLoadChunk); -+ final int queuedChunkZ = CoordinateUtils.getChunkZ(queuedLoadChunk); -+ this.world.chunkTaskScheduler.scheduleChunkLoad( -+ queuedChunkX, queuedChunkZ, ChunkStatus.EMPTY, false, PrioritisedExecutor.Priority.NORMAL, null -+ ); -+ if (this.removed) { -+ return; -+ } -+ } -+ } -+ -+ // try to progress chunk generations -+ while (!this.generatingQueue.isEmpty()) { -+ final long pendingGenChunk = this.generatingQueue.firstLong(); -+ final int pendingChunkX = CoordinateUtils.getChunkX(pendingGenChunk); -+ final int pendingChunkZ = CoordinateUtils.getChunkZ(pendingGenChunk); -+ final LevelChunk pending = this.world.chunkSource.getChunkAtIfLoadedMainThreadNoCache(pendingChunkX, pendingChunkZ); -+ if (pending == null) { -+ // nothing to do here -+ break; -+ } -+ -+ // chunk has generated, so we can take it out of queue -+ this.generatingQueue.dequeueLong(); -+ -+ final byte prev = this.chunkTicketStage.put(pendingGenChunk, CHUNK_TICKET_STAGE_GENERATED); -+ if (prev != CHUNK_TICKET_STAGE_GENERATING) { -+ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_GENERATING + ", not " + prev); -+ } -+ -+ // try to move to send queue -+ if (this.wantChunkSent(pendingChunkX, pendingChunkZ)) { -+ this.sendQueue.enqueue(pendingGenChunk); -+ } -+ // try to move to tick queue -+ if (this.wantChunkTicked(pendingChunkX, pendingChunkZ)) { -+ this.tickingQueue.enqueue(pendingGenChunk); -+ } -+ } -+ -+ // try to push more chunk generations -+ final long maxGens = Math.max(0L, Math.min(MAX_RATE, Math.min(this.genQueue.size(), this.getMaxChunkGenerates()))); -+ final int maxGensThisTick = (int)this.chunkGenerateTicketLimiter.takeAllocation(time, genRate, maxGens); -+ for (int i = 0; i < maxGensThisTick; ++i) { -+ final long chunk = this.genQueue.dequeueLong(); -+ final byte prev = this.chunkTicketStage.put(chunk, CHUNK_TICKET_STAGE_GENERATING); -+ if (prev != CHUNK_TICKET_STAGE_LOADED) { -+ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_LOADED + ", not " + prev); -+ } -+ this.pushDelayedTicketOp( -+ ChunkHolderManager.TicketOperation.addAndRemove( -+ chunk, -+ REGION_PLAYER_TICKET, GENERATED_TICKET_LEVEL, this.idBoxed, -+ REGION_PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed -+ ) -+ ); -+ this.generatingQueue.enqueue(chunk); -+ } -+ -+ // try to pull ticking chunks -+ tick_check_outer: -+ while (!this.tickingQueue.isEmpty()) { -+ final long pendingTicking = this.tickingQueue.firstLong(); -+ final int pendingChunkX = CoordinateUtils.getChunkX(pendingTicking); -+ final int pendingChunkZ = CoordinateUtils.getChunkZ(pendingTicking); -+ -+ final int tickingReq = 2; -+ for (int dz = -tickingReq; dz <= tickingReq; ++dz) { -+ for (int dx = -tickingReq; dx <= tickingReq; ++dx) { -+ if ((dx | dz) == 0) { -+ continue; -+ } -+ final long neighbour = CoordinateUtils.getChunkKey(dx + pendingChunkX, dz + pendingChunkZ); -+ final byte stage = this.chunkTicketStage.get(neighbour); -+ if (stage != CHUNK_TICKET_STAGE_GENERATED && stage != CHUNK_TICKET_STAGE_TICK) { -+ break tick_check_outer; -+ } -+ } -+ } -+ // only gets here if all neighbours were marked as generated or ticking themselves -+ this.tickingQueue.dequeueLong(); -+ this.pushDelayedTicketOp( -+ ChunkHolderManager.TicketOperation.addAndRemove( -+ pendingTicking, -+ REGION_PLAYER_TICKET, TICK_TICKET_LEVEL, this.idBoxed, -+ REGION_PLAYER_TICKET, GENERATED_TICKET_LEVEL, this.idBoxed -+ ) -+ ); -+ // there is no queue to add after ticking -+ final byte prev = this.chunkTicketStage.put(pendingTicking, CHUNK_TICKET_STAGE_TICK); -+ if (prev != CHUNK_TICKET_STAGE_GENERATED) { -+ throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_GENERATED + ", not " + prev); -+ } -+ } -+ -+ // try to pull sending chunks -+ final long maxSends = Math.max(0L, Math.min(MAX_RATE, Integer.MAX_VALUE)); // no logic to track concurrent sends -+ final int maxSendsThisTick = Math.min((int)this.chunkSendLimiter.takeAllocation(time, sendRate, maxSends), this.sendQueue.size()); -+ // we do not return sends that we took from the allocation back because we want to limit the max send rate, not target it -+ for (int i = 0; i < maxSendsThisTick; ++i) { -+ final long pendingSend = this.sendQueue.firstLong(); -+ final int pendingSendX = CoordinateUtils.getChunkX(pendingSend); -+ final int pendingSendZ = CoordinateUtils.getChunkZ(pendingSend); -+ final LevelChunk chunk = this.world.chunkSource.getChunkAtIfLoadedMainThreadNoCache(pendingSendX, pendingSendZ); -+ if (!chunk.areNeighboursLoaded(1) || !TickThread.isTickThreadFor(this.world, pendingSendX, pendingSendZ)) { -+ // nothing to do -+ // the target chunk may not be owned by this region, but this should be resolved in the future -+ break; -+ } -+ this.sendQueue.dequeueLong(); -+ -+ this.sendChunk(pendingSendX, pendingSendZ); -+ if (this.removed) { -+ // sendChunk may invoke plugin logic -+ return; -+ } -+ } -+ -+ this.flushDelayedTicketOps(); -+ // we assume propagate ticket levels happens after this call -+ } -+ -+ void add() { -+ TickThread.ensureTickThread(this.player, "Cannot add player asynchronously"); -+ if (this.removed) { -+ throw new IllegalStateException("Adding removed player chunk loader"); -+ } -+ final ViewDistances playerDistances = this.player.getViewDistances(); -+ final ViewDistances worldDistances = this.world.getViewDistances(); -+ final int chunkX = this.player.chunkPosition().x; -+ final int chunkZ = this.player.chunkPosition().z; -+ -+ final int tickViewDistance = getTickDistance(playerDistances.tickViewDistance, worldDistances.tickViewDistance); -+ // load view cannot be less-than tick view + 1 -+ final int loadViewDistance = getLoadViewDistance(tickViewDistance, playerDistances.loadViewDistance, worldDistances.loadViewDistance); -+ // send view cannot be greater-than load view -+ final int clientViewDistance = getClientViewDistance(this.player); -+ final int sendViewDistance = getSendViewDistance(loadViewDistance, clientViewDistance, playerDistances.sendViewDistance, worldDistances.sendViewDistance); -+ -+ // send view distances -+ this.player.connection.send(this.updateClientChunkRadius(sendViewDistance)); -+ this.player.connection.send(this.updateClientSimulationDistance(tickViewDistance)); -+ -+ // add to distance maps -+ this.broadcastMap.add(chunkX, chunkZ, sendViewDistance); -+ this.loadTicketCleanup.add(chunkX, chunkZ, loadViewDistance + 1); -+ this.tickMap.add(chunkX, chunkZ, tickViewDistance); -+ -+ // update chunk center -+ this.player.connection.send(this.updateClientChunkCenter(chunkX, chunkZ)); -+ -+ // now we can update -+ this.update(); -+ } -+ -+ private boolean isLoadedChunkGeneratable(final int chunkX, final int chunkZ) { -+ return this.isLoadedChunkGeneratable(this.world.chunkSource.getChunkAtImmediately(chunkX, chunkZ)); -+ } -+ -+ private boolean isLoadedChunkGeneratable(final ChunkAccess chunkAccess) { -+ final BelowZeroRetrogen belowZeroRetrogen; -+ return chunkAccess != null && ( -+ chunkAccess.getStatus() == ChunkStatus.FULL || -+ ((belowZeroRetrogen = chunkAccess.getBelowZeroRetrogen()) != null && belowZeroRetrogen.targetStatus().isOrAfter(ChunkStatus.FULL)) -+ ); -+ } -+ -+ void update() { -+ TickThread.ensureTickThread(this.player, "Cannot update player asynchronously"); -+ if (this.removed) { -+ throw new IllegalStateException("Updating removed player chunk loader"); -+ } -+ final ViewDistances playerDistances = this.player.getViewDistances(); -+ final ViewDistances worldDistances = this.world.getViewDistances(); -+ -+ final int tickViewDistance = getTickDistance(playerDistances.tickViewDistance, worldDistances.tickViewDistance); -+ // load view cannot be less-than tick view + 1 -+ final int loadViewDistance = getLoadViewDistance(tickViewDistance, playerDistances.loadViewDistance, worldDistances.loadViewDistance); -+ // send view cannot be greater-than load view -+ final int clientViewDistance = getClientViewDistance(this.player); -+ final int sendViewDistance = getSendViewDistance(loadViewDistance, clientViewDistance, playerDistances.sendViewDistance, worldDistances.sendViewDistance); -+ -+ final ChunkPos playerPos = this.player.chunkPosition(); -+ final boolean canGenerateChunks = this.canPlayerGenerateChunks(); -+ final int currentChunkX = playerPos.x; -+ final int currentChunkZ = playerPos.z; -+ -+ final int prevChunkX = this.lastChunkX; -+ final int prevChunkZ = this.lastChunkZ; -+ -+ if ( -+ // has view distance stayed the same? -+ sendViewDistance == this.lastSendDistance -+ && loadViewDistance == this.lastLoadDistance -+ && tickViewDistance == this.lastTickDistance -+ -+ // has our chunk stayed the same? -+ && prevChunkX == currentChunkX -+ && prevChunkZ == currentChunkZ -+ -+ // can we still generate chunks? -+ && this.canGenerateChunks == canGenerateChunks -+ ) { -+ // nothing we care about changed, so we're not re-calculating -+ return; -+ } -+ -+ // update distance maps -+ this.broadcastMap.update(currentChunkX, currentChunkZ, sendViewDistance); -+ this.loadTicketCleanup.update(currentChunkX, currentChunkZ, loadViewDistance + 1); -+ this.tickMap.update(currentChunkX, currentChunkZ, tickViewDistance); -+ if (sendViewDistance > loadViewDistance || tickViewDistance > loadViewDistance) { -+ throw new IllegalStateException(); -+ } -+ -+ // update VDs for client -+ // this should be after the distance map updates, as they will send unload packets -+ if (this.lastSentChunkRadius != sendViewDistance) { -+ this.player.connection.send(this.updateClientChunkRadius(sendViewDistance)); -+ } -+ if (this.lastSentSimulationDistance != tickViewDistance) { -+ this.player.connection.send(this.updateClientSimulationDistance(tickViewDistance)); -+ } -+ -+ this.sendQueue.clear(); -+ this.tickingQueue.clear(); -+ this.generatingQueue.clear(); -+ this.genQueue.clear(); -+ this.loadingQueue.clear(); -+ this.loadQueue.clear(); -+ -+ this.lastChunkX = currentChunkX; -+ this.lastChunkZ = currentChunkZ; -+ this.lastSendDistance = sendViewDistance; -+ this.lastLoadDistance = loadViewDistance; -+ this.lastTickDistance = tickViewDistance; -+ this.canGenerateChunks = canGenerateChunks; -+ -+ // +1 since we need to load chunks +1 around the load view distance... -+ final long[] toIterate = SEARCH_RADIUS_ITERATION_LIST[loadViewDistance + 1]; -+ // the iteration order is by increasing manhattan distance - so, we do NOT need to -+ // sort anything in the queue! -+ for (final long deltaChunk : toIterate) { -+ final int dx = CoordinateUtils.getChunkX(deltaChunk); -+ final int dz = CoordinateUtils.getChunkZ(deltaChunk); -+ final int chunkX = dx + currentChunkX; -+ final int chunkZ = dz + currentChunkZ; -+ final long chunk = CoordinateUtils.getChunkKey(chunkX, chunkZ); -+ final int squareDistance = Math.max(Math.abs(dx), Math.abs(dz)); -+ final int manhattanDistance = Math.abs(dx) + Math.abs(dz); -+ -+ // since chunk sending is not by radius alone, we need an extra check here to account for -+ // everything <= sendDistance -+ // Note: Vanilla may want to send chunks outside the send view distance, so we do need -+ // the dist <= view check -+ final boolean sendChunk = squareDistance <= sendViewDistance -+ && wantChunkLoaded(currentChunkX, currentChunkZ, chunkX, chunkZ, sendViewDistance); -+ final boolean sentChunk = sendChunk ? this.sentChunks.contains(chunk) : this.sentChunks.remove(chunk); -+ -+ if (!sendChunk && sentChunk) { -+ // have sent the chunk, but don't want it anymore -+ // unload it now -+ this.sendUnloadChunkRaw(chunkX, chunkZ); -+ } -+ -+ final byte stage = this.chunkTicketStage.get(chunk); -+ switch (stage) { -+ case CHUNK_TICKET_STAGE_NONE: { -+ // we want the chunk to be at least loaded -+ this.loadQueue.enqueue(chunk); -+ break; -+ } -+ case CHUNK_TICKET_STAGE_LOADING: { -+ this.loadingQueue.enqueue(chunk); -+ break; -+ } -+ case CHUNK_TICKET_STAGE_LOADED: { -+ if (canGenerateChunks || this.isLoadedChunkGeneratable(chunkX, chunkZ)) { -+ this.genQueue.enqueue(chunk); -+ } -+ break; -+ } -+ case CHUNK_TICKET_STAGE_GENERATING: { -+ this.generatingQueue.enqueue(chunk); -+ break; -+ } -+ case CHUNK_TICKET_STAGE_GENERATED: { -+ if (sendChunk && !sentChunk) { -+ this.sendQueue.enqueue(chunk); -+ } -+ if (squareDistance <= tickViewDistance) { -+ this.tickingQueue.enqueue(chunk); -+ } -+ break; -+ } -+ case CHUNK_TICKET_STAGE_TICK: { -+ if (sendChunk && !sentChunk) { -+ this.sendQueue.enqueue(chunk); -+ } -+ break; -+ } -+ default: { -+ throw new IllegalStateException("Unknown stage: " + stage); -+ } -+ } -+ } -+ -+ // update the chunk center -+ // this must be done last so that the client does not ignore any of our unload chunk packets above -+ if (this.lastSentChunkCenterX != currentChunkX || this.lastSentChunkCenterZ != currentChunkZ) { -+ this.player.connection.send(this.updateClientChunkCenter(currentChunkX, currentChunkZ)); -+ } -+ -+ this.flushDelayedTicketOps(); -+ } -+ -+ void remove() { -+ TickThread.ensureTickThread(this.player, "Cannot add player asynchronously"); -+ if (this.removed) { -+ throw new IllegalStateException("Removing removed player chunk loader"); -+ } -+ this.removed = true; -+ // sends the chunk unload packets -+ this.broadcastMap.remove(); -+ // cleans up loading/generating tickets -+ this.loadTicketCleanup.remove(); -+ // cleans up ticking tickets -+ this.tickMap.remove(); -+ -+ // purge queues -+ this.sendQueue.clear(); -+ this.tickingQueue.clear(); -+ this.generatingQueue.clear(); -+ this.genQueue.clear(); -+ this.loadingQueue.clear(); -+ this.loadQueue.clear(); -+ -+ // flush ticket changes -+ this.flushDelayedTicketOps(); -+ -+ // now all tickets should be removed, which is all of our external state -+ } -+ } -+ -+ // TODO rebase into util patch -+ private static final class AllocatingRateLimiter { -+ -+ // max difference granularity in ns -+ private static final long MAX_GRANULARITY = TimeUnit.SECONDS.toNanos(1L); -+ -+ private double allocation; -+ private long lastAllocationUpdate; -+ private double takeCarry; -+ private long lastTakeUpdate; -+ -+ // rate in units/s, and time in ns -+ public void tickAllocation(final long time, final double rate, final double maxAllocation) { -+ final long diff = Math.min(MAX_GRANULARITY, time - this.lastAllocationUpdate); -+ this.lastAllocationUpdate = time; -+ -+ this.allocation = Math.min(maxAllocation - this.takeCarry, this.allocation + rate * (diff*1.0E-9D)); -+ } -+ -+ // rate in units/s, and time in ns -+ public long takeAllocation(final long time, final double rate, final long maxTake) { -+ if (maxTake < 1L) { -+ return 0L; -+ } -+ -+ double ret = this.takeCarry; -+ final long diff = Math.min(MAX_GRANULARITY, time - this.lastTakeUpdate); -+ this.lastTakeUpdate = time; -+ -+ // note: abs(takeCarry) <= 1.0 -+ final double take = Math.min(Math.min((double)maxTake - this.takeCarry, this.allocation), rate * (diff*1.0E-9)); -+ -+ ret += take; -+ this.allocation -= take; -+ -+ final long retInteger = (long)Math.floor(ret); -+ this.takeCarry = ret - (double)retInteger; -+ -+ return retInteger; -+ } -+ } -+ -+ public static abstract class SingleUserAreaMap { -+ -+ private static final int NOT_SET = Integer.MIN_VALUE; -+ -+ private final T parameter; -+ private int lastChunkX = NOT_SET; -+ private int lastChunkZ = NOT_SET; -+ private int distance = NOT_SET; -+ -+ public SingleUserAreaMap(final T parameter) { -+ this.parameter = parameter; -+ } -+ -+ /* math sign function except 0 returns 1 */ -+ protected static int sign(int val) { -+ return 1 | (val >> (Integer.SIZE - 1)); -+ } -+ -+ protected abstract void addCallback(final T parameter, final int chunkX, final int chunkZ); -+ -+ protected abstract void removeCallback(final T parameter, final int chunkX, final int chunkZ); -+ -+ private void addToNew(final T parameter, final int chunkX, final int chunkZ, final int distance) { -+ final int maxX = chunkX + distance; -+ final int maxZ = chunkZ + distance; -+ -+ for (int cx = chunkX - distance; cx <= maxX; ++cx) { -+ for (int cz = chunkZ - distance; cz <= maxZ; ++cz) { -+ this.addCallback(parameter, cx, cz); -+ } -+ } -+ } -+ -+ private void removeFromOld(final T parameter, final int chunkX, final int chunkZ, final int distance) { -+ final int maxX = chunkX + distance; -+ final int maxZ = chunkZ + distance; -+ -+ for (int cx = chunkX - distance; cx <= maxX; ++cx) { -+ for (int cz = chunkZ - distance; cz <= maxZ; ++cz) { -+ this.removeCallback(parameter, cx, cz); -+ } -+ } -+ } -+ -+ public final boolean add(final int chunkX, final int chunkZ, final int distance) { -+ if (distance < 0) { -+ throw new IllegalArgumentException(Integer.toString(distance)); -+ } -+ if (this.lastChunkX != NOT_SET) { -+ return false; -+ } -+ this.lastChunkX = chunkX; -+ this.lastChunkZ = chunkZ; -+ this.distance = distance; -+ -+ this.addToNew(this.parameter, chunkX, chunkZ, distance); -+ -+ return true; -+ } -+ -+ public final boolean update(final int toX, final int toZ, final int newViewDistance) { -+ if (newViewDistance < 0) { -+ throw new IllegalArgumentException(Integer.toString(newViewDistance)); -+ } -+ final int fromX = this.lastChunkX; -+ final int fromZ = this.lastChunkZ; -+ final int oldViewDistance = this.distance; -+ if (fromX == NOT_SET) { -+ return false; -+ } -+ -+ this.lastChunkX = toX; -+ this.lastChunkZ = toZ; -+ -+ final T parameter = this.parameter; -+ -+ -+ final int dx = toX - fromX; -+ final int dz = toZ - fromZ; -+ -+ final int totalX = IntegerUtil.branchlessAbs(fromX - toX); -+ final int totalZ = IntegerUtil.branchlessAbs(fromZ - toZ); -+ -+ if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) { -+ // teleported? -+ this.removeFromOld(parameter, fromX, fromZ, oldViewDistance); -+ this.addToNew(parameter, toX, toZ, newViewDistance); -+ return true; -+ } -+ -+ if (oldViewDistance != newViewDistance) { -+ // remove loop -+ -+ final int oldMinX = fromX - oldViewDistance; -+ final int oldMinZ = fromZ - oldViewDistance; -+ final int oldMaxX = fromX + oldViewDistance; -+ final int oldMaxZ = fromZ + oldViewDistance; -+ for (int currX = oldMinX; currX <= oldMaxX; ++currX) { -+ for (int currZ = oldMinZ; currZ <= oldMaxZ; ++currZ) { -+ -+ // only remove if we're outside the new view distance... -+ if (Math.max(IntegerUtil.branchlessAbs(currX - toX), IntegerUtil.branchlessAbs(currZ - toZ)) > newViewDistance) { -+ this.removeCallback(parameter, currX, currZ); -+ } -+ } -+ } -+ -+ // add loop -+ -+ final int newMinX = toX - newViewDistance; -+ final int newMinZ = toZ - newViewDistance; -+ final int newMaxX = toX + newViewDistance; -+ final int newMaxZ = toZ + newViewDistance; -+ for (int currX = newMinX; currX <= newMaxX; ++currX) { -+ for (int currZ = newMinZ; currZ <= newMaxZ; ++currZ) { -+ -+ // only add if we're outside the old view distance... -+ if (Math.max(IntegerUtil.branchlessAbs(currX - fromX), IntegerUtil.branchlessAbs(currZ - fromZ)) > oldViewDistance) { -+ this.addCallback(parameter, currX, currZ); -+ } -+ } -+ } -+ -+ return true; -+ } -+ -+ // x axis is width -+ // z axis is height -+ // right refers to the x axis of where we moved -+ // top refers to the z axis of where we moved -+ -+ // same view distance -+ -+ // used for relative positioning -+ final int up = sign(dz); // 1 if dz >= 0, -1 otherwise -+ final int right = sign(dx); // 1 if dx >= 0, -1 otherwise -+ -+ // The area excluded by overlapping the two view distance squares creates four rectangles: -+ // Two on the left, and two on the right. The ones on the left we consider the "removed" section -+ // and on the right the "added" section. -+ // https://i.imgur.com/MrnOBgI.png is a reference image. Note that the outside border is not actually -+ // exclusive to the regions they surround. -+ -+ // 4 points of the rectangle -+ int maxX; // exclusive -+ int minX; // inclusive -+ int maxZ; // exclusive -+ int minZ; // inclusive -+ -+ if (dx != 0) { -+ // handle right addition -+ -+ maxX = toX + (oldViewDistance * right) + right; // exclusive -+ minX = fromX + (oldViewDistance * right) + right; // inclusive -+ maxZ = fromZ + (oldViewDistance * up) + up; // exclusive -+ minZ = toZ - (oldViewDistance * up); // inclusive -+ -+ for (int currX = minX; currX != maxX; currX += right) { -+ for (int currZ = minZ; currZ != maxZ; currZ += up) { -+ this.addCallback(parameter, currX, currZ); -+ } -+ } -+ } -+ -+ if (dz != 0) { -+ // handle up addition -+ -+ maxX = toX + (oldViewDistance * right) + right; // exclusive -+ minX = toX - (oldViewDistance * right); // inclusive -+ maxZ = toZ + (oldViewDistance * up) + up; // exclusive -+ minZ = fromZ + (oldViewDistance * up) + up; // inclusive -+ -+ for (int currX = minX; currX != maxX; currX += right) { -+ for (int currZ = minZ; currZ != maxZ; currZ += up) { -+ this.addCallback(parameter, currX, currZ); -+ } -+ } -+ } -+ -+ if (dx != 0) { -+ // handle left removal -+ -+ maxX = toX - (oldViewDistance * right); // exclusive -+ minX = fromX - (oldViewDistance * right); // inclusive -+ maxZ = fromZ + (oldViewDistance * up) + up; // exclusive -+ minZ = toZ - (oldViewDistance * up); // inclusive -+ -+ for (int currX = minX; currX != maxX; currX += right) { -+ for (int currZ = minZ; currZ != maxZ; currZ += up) { -+ this.removeCallback(parameter, currX, currZ); -+ } -+ } -+ } -+ -+ if (dz != 0) { -+ // handle down removal -+ -+ maxX = fromX + (oldViewDistance * right) + right; // exclusive -+ minX = fromX - (oldViewDistance * right); // inclusive -+ maxZ = toZ - (oldViewDistance * up); // exclusive -+ minZ = fromZ - (oldViewDistance * up); // inclusive -+ -+ for (int currX = minX; currX != maxX; currX += right) { -+ for (int currZ = minZ; currZ != maxZ; currZ += up) { -+ this.removeCallback(parameter, currX, currZ); -+ } -+ } -+ } -+ -+ return true; -+ } -+ -+ public final boolean remove() { -+ final int chunkX = this.lastChunkX; -+ final int chunkZ = this.lastChunkZ; -+ final int distance = this.distance; -+ if (chunkX == NOT_SET) { -+ return false; -+ } -+ -+ this.lastChunkX = this.lastChunkZ = this.distance = NOT_SET; -+ -+ this.removeFromOld(this.parameter, chunkX, chunkZ, distance); -+ -+ return true; -+ } -+ } -+ -+ static final class CountedSRSWLinkedQueue { -+ -+ private final SRSWLinkedQueue queue = new SRSWLinkedQueue<>(); -+ private volatile long countAdded; -+ private volatile long countRemoved; -+ -+ private static final VarHandle COUNT_ADDED_HANDLE = ConcurrentUtil.getVarHandle(CountedSRSWLinkedQueue.class, "countAdded", long.class); -+ private static final VarHandle COUNT_REMOVED_HANDLE = ConcurrentUtil.getVarHandle(CountedSRSWLinkedQueue.class, "countRemoved", long.class); -+ -+ private long getCountAddedPlain() { -+ return (long)COUNT_ADDED_HANDLE.get(this); -+ } -+ -+ private long getCountAddedAcquire() { -+ return (long)COUNT_ADDED_HANDLE.getAcquire(this); -+ } -+ -+ private void setCountAddedRelease(final long to) { -+ COUNT_ADDED_HANDLE.setRelease(this, to); -+ } -+ -+ private long getCountRemovedPlain() { -+ return (long)COUNT_REMOVED_HANDLE.get(this); -+ } -+ -+ private long getCountRemovedAcquire() { -+ return (long)COUNT_REMOVED_HANDLE.getAcquire(this); -+ } -+ -+ private void setCountRemovedRelease(final long to) { -+ COUNT_REMOVED_HANDLE.setRelease(this, to); -+ } -+ -+ public void add(final E element) { -+ this.setCountAddedRelease(this.getCountAddedPlain() + 1L); -+ this.queue.addLast(element); -+ } -+ -+ public E poll() { -+ final E ret = this.queue.poll(); -+ if (ret != null) { -+ this.setCountRemovedRelease(this.getCountRemovedPlain() + 1L); -+ } -+ -+ return ret; -+ } -+ -+ public long size() { -+ final long removed = this.getCountRemovedAcquire(); -+ final long added = this.getCountAddedAcquire(); -+ -+ return added - removed; -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -index 748cc48c6c42c694d1c9b685e96fbe6d8337d3f3..ce26fdfa1afc74ba93d19157042f6c55778011e1 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -@@ -1,5 +1,6 @@ - package io.papermc.paper.chunk.system.scheduling; - -+import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue; - import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; - import ca.spottedleaf.concurrentutil.map.SWMRLong2ObjectHashTable; - import co.aikar.timings.Timing; -@@ -500,6 +501,21 @@ public final class ChunkHolderManager { - } - } - -+ // atomic with respect to all add/remove/addandremove ticket calls for the given chunk -+ public boolean addIfRemovedTicket(final long chunk, final TicketType addType, final int addLevel, final T addIdentifier, -+ final TicketType removeType, final int removeLevel, final V removeIdentifier) { -+ this.ticketLock.lock(); -+ try { -+ if (this.removeTicketAtLevel(removeType, chunk, removeLevel, removeIdentifier)) { -+ this.addTicketAtLevel(addType, chunk, addLevel, addIdentifier); -+ return true; -+ } -+ return false; -+ } finally { -+ this.ticketLock.unlock(); -+ } -+ } -+ - public void removeAllTicketsFor(final TicketType ticketType, final int ticketLevel, final T ticketIdentifier) { - if (ticketLevel > MAX_TICKET_LEVEL) { - return; -@@ -907,6 +923,142 @@ public final class ChunkHolderManager { - } - } - -+ public enum TicketOperationType { -+ ADD, REMOVE, ADD_IF_REMOVED, ADD_AND_REMOVE -+ } -+ -+ public static record TicketOperation ( -+ TicketOperationType op, long chunkCoord, -+ TicketType ticketType, int ticketLevel, T identifier, -+ TicketType ticketType2, int ticketLevel2, V identifier2 -+ ) { -+ -+ private TicketOperation(TicketOperationType op, long chunkCoord, -+ TicketType ticketType, int ticketLevel, T identifier) { -+ this(op, chunkCoord, ticketType, ticketLevel, identifier, null, 0, null); -+ } -+ -+ public static TicketOperation addOp(final ChunkPos chunk, final TicketType type, final int ticketLevel, final T identifier) { -+ return addOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier); -+ } -+ -+ public static TicketOperation addOp(final int chunkX, final int chunkZ, final TicketType type, final int ticketLevel, final T identifier) { -+ return addOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier); -+ } -+ -+ public static TicketOperation addOp(final long chunk, final TicketType type, final int ticketLevel, final T identifier) { -+ return new TicketOperation<>(TicketOperationType.ADD, chunk, type, ticketLevel, identifier); -+ } -+ -+ public static TicketOperation removeOp(final ChunkPos chunk, final TicketType type, final int ticketLevel, final T identifier) { -+ return removeOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier); -+ } -+ -+ public static TicketOperation removeOp(final int chunkX, final int chunkZ, final TicketType type, final int ticketLevel, final T identifier) { -+ return removeOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier); -+ } -+ -+ public static TicketOperation removeOp(final long chunk, final TicketType type, final int ticketLevel, final T identifier) { -+ return new TicketOperation<>(TicketOperationType.REMOVE, chunk, type, ticketLevel, identifier); -+ } -+ -+ public static TicketOperation addIfRemovedOp(final long chunk, -+ final TicketType addType, final int addLevel, final T addIdentifier, -+ final TicketType removeType, final int removeLevel, final V removeIdentifier) { -+ return new TicketOperation<>( -+ TicketOperationType.ADD_IF_REMOVED, chunk, addType, addLevel, addIdentifier, -+ removeType, removeLevel, removeIdentifier -+ ); -+ } -+ -+ public static TicketOperation addAndRemove(final long chunk, -+ final TicketType addType, final int addLevel, final T addIdentifier, -+ final TicketType removeType, final int removeLevel, final V removeIdentifier) { -+ return new TicketOperation<>( -+ TicketOperationType.ADD_AND_REMOVE, chunk, addType, addLevel, addIdentifier, -+ removeType, removeLevel, removeIdentifier -+ ); -+ } -+ } -+ -+ private final MultiThreadedQueue> delayedTicketUpdates = new MultiThreadedQueue<>(); -+ -+ // note: MUST hold ticket lock, otherwise operation ordering is lost -+ private boolean drainTicketUpdates() { -+ boolean ret = false; -+ -+ TicketOperation operation; -+ while ((operation = this.delayedTicketUpdates.poll()) != null) { -+ switch (operation.op) { -+ case ADD: { -+ ret |= this.addTicketAtLevel(operation.ticketType, operation.chunkCoord, operation.ticketLevel, operation.identifier); -+ break; -+ } -+ case REMOVE: { -+ ret |= this.removeTicketAtLevel(operation.ticketType, operation.chunkCoord, operation.ticketLevel, operation.identifier); -+ break; -+ } -+ case ADD_IF_REMOVED: { -+ ret |= this.addIfRemovedTicket( -+ operation.chunkCoord, -+ operation.ticketType, operation.ticketLevel, operation.identifier, -+ operation.ticketType2, operation.ticketLevel2, operation.identifier2 -+ ); -+ break; -+ } -+ case ADD_AND_REMOVE: { -+ ret = true; -+ this.addAndRemoveTickets( -+ operation.chunkCoord, -+ operation.ticketType, operation.ticketLevel, operation.identifier, -+ operation.ticketType2, operation.ticketLevel2, operation.identifier2 -+ ); -+ break; -+ } -+ } -+ } -+ -+ return ret; -+ } -+ -+ public Boolean tryDrainTicketUpdates() { -+ final boolean acquired = this.ticketLock.tryLock(); -+ try { -+ if (!acquired) { -+ return null; -+ } -+ -+ return Boolean.valueOf(this.drainTicketUpdates()); -+ } finally { -+ if (acquired) { -+ this.ticketLock.unlock(); -+ } -+ } -+ } -+ -+ public void pushDelayedTicketUpdate(final TicketOperation operation) { -+ this.delayedTicketUpdates.add(operation); -+ } -+ -+ public void pushDelayedTicketUpdates(final Collection> operations) { -+ this.delayedTicketUpdates.addAll(operations); -+ } -+ -+ public Boolean tryProcessTicketUpdates() { -+ final boolean acquired = this.ticketLock.tryLock(); -+ try { -+ if (!acquired) { -+ return null; -+ } -+ -+ return Boolean.valueOf(this.processTicketUpdates(false, true, null)); -+ } finally { -+ if (acquired) { -+ this.ticketLock.unlock(); -+ } -+ } -+ } -+ - private final ThreadLocal BLOCK_TICKET_UPDATES = ThreadLocal.withInitial(() -> { - return Boolean.FALSE; - }); -@@ -953,6 +1105,8 @@ public final class ChunkHolderManager { - - this.ticketLock.lock(); - try { -+ this.drainTicketUpdates(); -+ - final boolean levelsUpdated = this.ticketLevelPropagator.propagateUpdates(); - if (levelsUpdated) { - // Unlike CB, ticket level updates cannot happen recursively. Thank god. -diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -index 52b02cb1f02d1c65b840f38cfc8baee500aa2259..09234062090c210227350cafeed141f8cb73108a 100644 ---- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -274,4 +274,43 @@ public class GlobalConfiguration extends ConfigurationPart { - public boolean useDimensionTypeForCustomSpawners = false; - public boolean strictAdvancementDimensionCheck = false; - } -+ -+ public ChunkLoadingBasic chunkLoadingBasic; -+ -+ public class ChunkLoadingBasic extends ConfigurationPart { -+ @Comment("The maximum rate in chunks per second that the server will send to any individual player. Set to -1 to disable this limit.") -+ public double playerMaxChunkSendRate = 75.0; -+ -+ @Comment( -+ "The maximum rate at which chunks will load for any individual player. " + -+ "Note that this setting also affects chunk generations, since a chunk load is always first issued to test if a" + -+ "chunk is already generated. Set to -1 to disable this limit." -+ ) -+ public double playerMaxChunkLoadRate = 100.0; -+ -+ @Comment("The maximum rate at which chunks will generate for any individual player. Set to -1 to disable this limit.") -+ public double playerMaxChunkGenerateRate = -1.0; -+ } -+ -+ public ChunkLoadingAdvanced chunkLoadingAdvanced; -+ -+ public class ChunkLoadingAdvanced extends ConfigurationPart { -+ @Comment( -+ "Set to true if the server will match the chunk send radius that clients have configured" + -+ "in their view distance settings if the client is less-than the server's send distance." -+ ) -+ public boolean autoConfigSendDistance = true; -+ -+ @Comment( -+ "Specifies the maximum amount of concurrent chunk loads that an individual player can have." + -+ "Set to 0 to let the server configure it automatically per player, or set it to -1 to disable the limit." -+ ) -+ public int playerMaxConcurrentChunkLoads = 0; -+ -+ @Comment( -+ "Specifies the maximum amount of concurrent chunk generations that an individual player can have." + -+ "Set to 0 to let the server configure it automatically per player, or set it to -1 to disable the limit." -+ ) -+ public int playerMaxConcurrentChunkGenerates = 0; -+ } - } -diff --git a/src/main/java/io/papermc/paper/util/IntervalledCounter.java b/src/main/java/io/papermc/paper/util/IntervalledCounter.java -index cea9c098ade00ee87b8efc8164ab72f5279758f0..197224e31175252d8438a8df585bbb65f2288d7f 100644 ---- a/src/main/java/io/papermc/paper/util/IntervalledCounter.java -+++ b/src/main/java/io/papermc/paper/util/IntervalledCounter.java -@@ -2,6 +2,8 @@ package io.papermc.paper.util; - - public final class IntervalledCounter { - -+ private static final int INITIAL_SIZE = 8; -+ - protected long[] times; - protected long[] counts; - protected final long interval; -@@ -11,8 +13,8 @@ public final class IntervalledCounter { - protected int tail; // exclusive - - public IntervalledCounter(final long interval) { -- this.times = new long[8]; -- this.counts = new long[8]; -+ this.times = new long[INITIAL_SIZE]; -+ this.counts = new long[INITIAL_SIZE]; - this.interval = interval; - } - -@@ -67,13 +69,13 @@ public final class IntervalledCounter { - this.tail = nextTail; - } - -- public void updateAndAdd(final int count) { -+ public void updateAndAdd(final long count) { - final long currTime = System.nanoTime(); - this.updateCurrentTime(currTime); - this.addTime(currTime, count); - } - -- public void updateAndAdd(final int count, final long currTime) { -+ public void updateAndAdd(final long count, final long currTime) { - this.updateCurrentTime(currTime); - this.addTime(currTime, count); - } -@@ -93,9 +95,13 @@ public final class IntervalledCounter { - this.tail = size; - - if (tail >= head) { -+ // sequentially ordered from [head, tail) - System.arraycopy(oldElements, head, newElements, 0, size); - System.arraycopy(oldCounts, head, newCounts, 0, size); - } else { -+ // ordered from [head, length) -+ // then followed by [0, tail) -+ - System.arraycopy(oldElements, head, newElements, 0, oldElements.length - head); - System.arraycopy(oldElements, 0, newElements, oldElements.length - head, tail); - -@@ -106,10 +112,18 @@ public final class IntervalledCounter { - - // returns in units per second - public double getRate() { -- return this.size() / (this.interval * 1.0e-9); -+ return (double)this.sum / ((double)this.interval * 1.0E-9); -+ } -+ -+ public long getInterval() { -+ return this.interval; - } - -- public long size() { -+ public long getSum() { - return this.sum; - } -+ -+ public int totalDataPoints() { -+ return this.tail >= this.head ? (this.tail - this.head) : (this.tail + (this.counts.length - this.head)); -+ } - } -diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index d58d44faa40be2421f4cb54740a3abdbad72875c..2e830847155e7c43ef411d28e81592c21446143b 100644 ---- a/src/main/java/io/papermc/paper/util/MCUtil.java -+++ b/src/main/java/io/papermc/paper/util/MCUtil.java -@@ -583,8 +583,8 @@ public final class MCUtil { - - worldData.addProperty("is-loaded", loadedWorlds.contains(bukkitWorld)); - worldData.addProperty("name", world.getWorld().getName()); -- worldData.addProperty("view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance()); // Paper - replace chunk loader system -- worldData.addProperty("tick-view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance()); // Paper - replace chunk loader system -+ worldData.addProperty("view-distance", world.getWorld().getViewDistance()); // Paper - replace chunk loader system -+ worldData.addProperty("tick-view-distance", world.getWorld().getSimulationDistance()); // Paper - replace chunk loader system - worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); - worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16); - -diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 6b6d31e76f48a0de33ac528f990ce841dbd666f1..4b87f5d899e5ac033d78ccdbca21c9c50c46dcef 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkHolder.java -+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -96,6 +96,25 @@ public class ChunkHolder { - - public final io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder; // Paper - rewrite chunk system - -+ // Paper start - replace player chunk loader -+ private final com.destroystokyo.paper.util.maplist.ReferenceList playersSentChunkTo = new com.destroystokyo.paper.util.maplist.ReferenceList<>(); -+ -+ public void addPlayer(ServerPlayer player) { -+ if (!this.playersSentChunkTo.add(player)) { -+ throw new IllegalStateException("Already sent chunk " + this.pos + " in world '" + this.chunkMap.level.getWorld().getName() + "' to player " + player); -+ } -+ } -+ -+ public void removePlayer(ServerPlayer player) { -+ if (!this.playersSentChunkTo.remove(player)) { -+ throw new IllegalStateException("Have not sent chunk " + this.pos + " in world '" + this.chunkMap.level.getWorld().getName() + "' to player " + player); -+ } -+ } -+ -+ public boolean hasChunkBeenSent() { -+ return this.playersSentChunkTo.size() != 0; -+ } -+ // Paper end - replace player chunk loader - public ChunkHolder(ChunkPos pos, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.PlayerProvider playersWatchingChunkProvider, io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder) { // Paper - rewrite chunk system - this.newChunkHolder = newChunkHolder; // Paper - rewrite chunk system - this.chunkToSaveHistory = null; -@@ -193,6 +212,11 @@ public class ChunkHolder { - // Paper - rewrite chunk system - - public void blockChanged(BlockPos pos) { -+ // Paper start - replace player chunk loader -+ if (this.playersSentChunkTo.size() == 0) { -+ return; -+ } -+ // Paper end - replace player chunk loader - LevelChunk chunk = this.getSendingChunk(); // Paper - no-tick view distance - - if (chunk != null) { -@@ -219,7 +243,7 @@ public class ChunkHolder { - LevelChunk chunk = this.getSendingChunk(); - // Paper end - no-tick view distance - -- if (chunk != null) { -+ if (this.playersSentChunkTo.size() != 0 && chunk != null) { // Paper - replace player chunk loader - int j = this.lightEngine.getMinLightSection(); - int k = this.lightEngine.getMaxLightSection(); - -@@ -316,25 +340,12 @@ public class ChunkHolder { - - // Paper start - rewrite chunk system - public List getPlayers(boolean onlyOnWatchDistanceEdge){ -- // Paper start - per player view distance - List ret = new java.util.ArrayList<>(); -- // there can be potential desync with player's last mapped section and the view distance map, so use the -- // view distance map here. -- com.destroystokyo.paper.util.misc.PlayerAreaMap viewDistanceMap = this.chunkMap.playerChunkManager.broadcastMap; // Paper - replace old player chunk manager -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet players = viewDistanceMap.getObjectsInRange(this.pos); -- if (players == null) { -- return ret; -- } -- -- Object[] backingSet = players.getBackingSet(); -- for (int i = 0, len = backingSet.length; i < len; ++i) { -- if (!(backingSet[i] instanceof ServerPlayer player)) { -+ for (int i = 0, len = this.playersSentChunkTo.size(); i < len; ++i) { -+ ServerPlayer player = this.playersSentChunkTo.getUnchecked(i); -+ if (onlyOnWatchDistanceEdge && !this.chunkMap.level.playerChunkLoader.isChunkSent(player, this.pos.x, this.pos.z, onlyOnWatchDistanceEdge)) { - continue; - } -- if (!this.chunkMap.playerChunkManager.isChunkSent(player, this.pos.x, this.pos.z, onlyOnWatchDistanceEdge)) { -- continue; -- } -- - ret.add(player); - } - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 284393fd4ae0a7562b6bc9b60cf2c141a2de3a58..a502d293cedb2f507e6cf1792429b36685ed1910 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -156,17 +156,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - // Paper start - distance maps - private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); -- public final io.papermc.paper.chunk.PlayerChunkLoader playerChunkManager = new io.papermc.paper.chunk.PlayerChunkLoader(this, this.pooledLinkedPlayerHashSets); // Paper - replace chunk loader - - void addPlayerToDistanceMaps(ServerPlayer player) { -- this.playerChunkManager.addPlayer(player); // Paper - replace chunk loader -+ this.level.playerChunkLoader.addPlayer(player); // Paper - replace chunk loader - int chunkX = MCUtil.getChunkCoordinate(player.getX()); - int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); - // Note: players need to be explicitly added to distance maps before they can be updated - } - - void removePlayerFromDistanceMaps(ServerPlayer player) { -- this.playerChunkManager.removePlayer(player); // Paper - replace chunk loader -+ this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader - - } - -@@ -174,7 +173,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - int chunkX = MCUtil.getChunkCoordinate(player.getX()); - int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); - // Note: players need to be explicitly added to distance maps before they can be updated -- this.playerChunkManager.updatePlayer(player); // Paper - replace chunk loader -+ this.level.playerChunkLoader.updatePlayer(player); // Paper - replace chunk loader - } - // Paper end - // Paper start -@@ -573,7 +572,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - // Paper start - replace player loader system - public void setTickViewDistance(int distance) { -- this.playerChunkManager.setTickDistance(distance); -+ this.level.playerChunkLoader.setTickDistance(distance); -+ } -+ -+ public void setSendViewDistance(int distance) { -+ this.level.playerChunkLoader.setSendDistance(distance); - } - // Paper end - replace player loader system - public void setViewDistance(int watchDistance) { -@@ -583,20 +586,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - int k = this.viewDistance; - - this.viewDistance = j; -- this.playerChunkManager.setLoadDistance(this.viewDistance); // Paper - replace player loader system -+ this.level.playerChunkLoader.setLoadDistance(this.viewDistance); // Paper - replace player loader system - } - - } - - public void updateChunkTracking(ServerPlayer player, ChunkPos pos, MutableObject packet, boolean oldWithinViewDistance, boolean newWithinViewDistance) { // Paper - public -+ io.papermc.paper.util.TickThread.ensureTickThread(this.level, pos, "May not update chunk tracking for chunk async"); // Paper - replace chunk loader system -+ io.papermc.paper.util.TickThread.ensureTickThread(player, "May not update chunk tracking for player async"); // Paper - replace chunk loader system - if (player.level() == this.level) { -+ ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); // Paper - replace chunk loader system - move up - if (newWithinViewDistance && !oldWithinViewDistance) { -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); -+ // Paper - replace chunk loader system - move up - - if (playerchunk != null) { - LevelChunk chunk = playerchunk.getSendingChunk(); // Paper - replace chunk loader system - - if (chunk != null) { -+ playerchunk.addPlayer(player); // Paper - replace chunk loader system - this.playerLoadedChunk(player, packet, chunk); - } - -@@ -605,10 +612,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - if (!newWithinViewDistance && oldWithinViewDistance) { -+ // Paper start - replace chunk loader system -+ if (playerchunk != null) { -+ playerchunk.removePlayer(player); -+ } else { -+ LOGGER.warn("ChunkHolder at " + pos + " in world '" + this.level.getWorld().getName() + "' does not exist to untrack chunk for " + player, new Throwable()); -+ } -+ // Paper end - replace chunk loader system - player.untrackChunk(pos); - } - -- } -+ } else { LOGGER.warn("Mismatch in world for chunk " + pos + " in world '" + this.level.getWorld().getName() + "' for player " + player, new Throwable()); } // Paper - replace chunk loader system - } - - public int size() { -@@ -842,34 +856,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper - replaced by PlayerChunkLoader - - this.updateMaps(player); // Paper - distance maps -- this.playerChunkManager.updatePlayer(player); // Paper - respond to movement immediately - - } - - @Override - public List getPlayers(ChunkPos chunkPos, boolean onlyOnWatchDistanceEdge) { - // Paper start - per player view distance -- // there can be potential desync with player's last mapped section and the view distance map, so use the -- // view distance map here. -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet players = this.playerChunkManager.broadcastMap.getObjectsInRange(chunkPos); -- if (players == null) { -- return java.util.Collections.emptyList(); -- } -- -- List ret = new java.util.ArrayList<>(players.size()); -- -- Object[] backingSet = players.getBackingSet(); -- for (int i = 0, len = backingSet.length; i < len; ++i) { -- if (!(backingSet[i] instanceof ServerPlayer player)) { -- continue; -- } -- if (!this.playerChunkManager.isChunkSent(player, chunkPos.x, chunkPos.z, onlyOnWatchDistanceEdge)) { -- continue; -- } -- ret.add(player); -+ ChunkHolder holder = this.getVisibleChunkIfPresent(chunkPos.toLong()); -+ if (holder == null) { -+ return new java.util.ArrayList<>(); -+ } else { -+ return holder.getPlayers(onlyOnWatchDistanceEdge); - } -- -- return ret; - // Paper end - per player view distance - } - -@@ -1179,7 +1177,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot - if (player != this.entity) { - Vec3 vec3d = player.position().subtract(this.entity.position()); -- double d0 = (double) Math.min(this.getEffectiveRange(), io.papermc.paper.chunk.PlayerChunkLoader.getSendViewDistance(player) * 16); // Paper - per player view distance -+ double d0 = (double) Math.min(this.getEffectiveRange(), io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player) * 16); // Paper - per player view distance - double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; - double d2 = d0 * d0; - boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player); -diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 32a07573ee23f01c98e684aefb45ff72802c9db6..20d600d29c2f2e47c798721d1f151e625b12acc3 100644 ---- a/src/main/java/net/minecraft/server/level/DistanceManager.java -+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -178,17 +178,17 @@ public abstract class DistanceManager { - } - - protected void updatePlayerTickets(int viewDistance) { -- this.chunkMap.playerChunkManager.setTargetNoTickViewDistance(viewDistance); // Paper - route to player chunk manager -+ this.chunkMap.setViewDistance(viewDistance);// Paper - route to player chunk manager - } - - // Paper start - public int getSimulationDistance() { -- return this.chunkMap.playerChunkManager.getTargetTickViewDistance(); // Paper - route to player chunk manager -+ return this.chunkMap.level.playerChunkLoader.getAPITickDistance(); - } - // Paper end - - public void updateSimulationDistance(int simulationDistance) { -- this.chunkMap.playerChunkManager.setTargetTickViewDistance(simulationDistance); // Paper - route to player chunk manager -+ this.chunkMap.level.playerChunkLoader.setTickDistance(simulationDistance); // Paper - route to player chunk manager - } - - public int getNaturalSpawnChunkCount() { -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index bb7b7f904639ac964f9c2d1bd5a660d8b397f647..caff28e2446177d622c999b84d8889fbf61d0b3d 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -661,7 +661,7 @@ public class ServerChunkCache extends ChunkSource { - this.level.getProfiler().popPush("chunks"); - if (tickChunks) { - this.level.timings.chunks.startTiming(); // Paper - timings -- this.chunkMap.playerChunkManager.tick(); // Paper - this is mostly is to account for view distance changes -+ this.chunkMap.level.playerChunkLoader.tick(); // Paper - replace player chunk loader - this is mostly required to account for view distance changes - this.tickChunks(); - this.level.timings.chunks.stopTiming(); // Paper - timings - } -@@ -929,7 +929,7 @@ public class ServerChunkCache extends ChunkSource { - @Override - // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task - public boolean pollTask() { -- ServerChunkCache.this.chunkMap.playerChunkManager.tickMidTick(); -+ // Paper - replace player chunk loader - if (ServerChunkCache.this.runDistanceManagerUpdates()) { - return true; - } -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index d7172df2489f2eb325120d950dcff32cc483db56..62a95a0fac59683948f34b202e6e3859b6652d6d 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -423,6 +423,48 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - // Paper end - rewrite chunk system - -+ public final io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader playerChunkLoader = new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader(this); -+ private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); -+ -+ public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances getViewDistances() { -+ return this.viewDistances.get(); -+ } -+ -+ private void updateViewDistance(final java.util.function.Function update) { -+ for (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances curr = this.viewDistances.get();;) { -+ if (this.viewDistances.compareAndSet(curr, update.apply(curr))) { -+ return; -+ } -+ } -+ } -+ -+ public void setTickViewDistance(final int distance) { -+ if ((distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE)) { -+ throw new IllegalArgumentException("Tick view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE) + ", got: " + distance); -+ } -+ this.updateViewDistance((input) -> { -+ return input.setTickViewDistance(distance); -+ }); -+ } -+ -+ public void setLoadViewDistance(final int distance) { -+ if (distance != -1 && (distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1)) { -+ throw new IllegalArgumentException("Load view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1) + " or -1, got: " + distance); -+ } -+ this.updateViewDistance((input) -> { -+ return input.setLoadViewDistance(distance); -+ }); -+ } -+ -+ public void setSendViewDistance(final int distance) { -+ if (distance != -1 && (distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1)) { -+ throw new IllegalArgumentException("Send view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1) + " or -1, got: " + distance); -+ } -+ this.updateViewDistance((input) -> { -+ return input.setSendViewDistance(distance); -+ }); -+ } -+ - // Add env and gen to constructor, IWorldDataServer -> WorldDataServer - public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { - // IRegistryCustom.Dimension iregistrycustom_dimension = minecraftserver.registryAccess(); // CraftBukkit - decompile error -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 5872ead2fe3a64f02f8bc36603fbb856728fd255..32ef9f1ae0c35e927133572ebb6fbf50b0729a63 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -260,6 +260,48 @@ public class ServerPlayer extends Player { - public boolean isRealPlayer; // Paper - public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet cachedSingleHashSet; // Paper - -+ private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); -+ public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader; -+ -+ public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances getViewDistances() { -+ return this.viewDistances.get(); -+ } -+ -+ private void updateViewDistance(final java.util.function.Function update) { -+ for (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances curr = this.viewDistances.get();;) { -+ if (this.viewDistances.compareAndSet(curr, update.apply(curr))) { -+ return; -+ } -+ } -+ } -+ -+ public void setTickViewDistance(final int distance) { -+ if ((distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE)) { -+ throw new IllegalArgumentException("Tick view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE) + ", got: " + distance); -+ } -+ this.updateViewDistance((input) -> { -+ return input.setTickViewDistance(distance); -+ }); -+ } -+ -+ public void setLoadViewDistance(final int distance) { -+ if (distance != -1 && (distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1)) { -+ throw new IllegalArgumentException("Load view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1) + " or -1, got: " + distance); -+ } -+ this.updateViewDistance((input) -> { -+ return input.setLoadViewDistance(distance); -+ }); -+ } -+ -+ public void setSendViewDistance(final int distance) { -+ if (distance != -1 && (distance < io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE || distance > io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1)) { -+ throw new IllegalArgumentException("Send view distance must be a number between " + io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MIN_VIEW_DISTANCE + " and " + (io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.MAX_VIEW_DISTANCE + 1) + " or -1, got: " + distance); -+ } -+ this.updateViewDistance((input) -> { -+ return input.setSendViewDistance(distance); -+ }); -+ } -+ - public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile) { - super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); - this.chatVisibility = ChatVisiblity.FULL; -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index d4f44635b3cb7ac890ea89b6f4454fa9d4375c08..0338a6b245ee482d470f5a80da712679ab9890fa 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -262,7 +262,7 @@ public abstract class PlayerList { - boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO); - - // Spigot - view distance -- playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), this.server.levelKeys(), this.synchronizedRegistries, worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), this.getMaxPlayers(), worldserver1.getChunkSource().chunkMap.playerChunkManager.getTargetSendDistance(), worldserver1.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance(), flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat(), player.getLastDeathLocation(), player.getPortalCooldown())); // Paper - replace old player chunk management -+ playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), this.server.levelKeys(), this.synchronizedRegistries, worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), this.getMaxPlayers(), worldserver1.getWorld().getSendViewDistance(), worldserver1.getWorld().getSimulationDistance(), flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat(), player.getLastDeathLocation(), player.getPortalCooldown())); // Paper - replace old player chunk management - player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit - playerconnection.send(new ClientboundUpdateEnabledFeaturesPacket(FeatureFlags.REGISTRY.toNames(worldserver1.enabledFeatures()))); - playerconnection.send(new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, (new FriendlyByteBuf(Unpooled.buffer())).writeUtf(this.getServer().getServerModName()))); -@@ -800,8 +800,8 @@ public abstract class PlayerList { - // CraftBukkit start - LevelData worlddata = worldserver1.getLevelData(); - entityplayer1.connection.send(new ClientboundRespawnPacket(worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), entityplayer1.gameMode.getGameModeForPlayer(), entityplayer1.gameMode.getPreviousGameModeForPlayer(), worldserver1.isDebug(), worldserver1.isFlat(), (byte) i, entityplayer1.getLastDeathLocation(), entityplayer1.getPortalCooldown())); -- entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.getChunkSource().chunkMap.playerChunkManager.getTargetSendDistance())); // Spigot // Paper - replace old player chunk management -- entityplayer1.connection.send(new ClientboundSetSimulationDistancePacket(worldserver1.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance())); // Spigot // Paper - replace old player chunk management -+ entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.getWorld().getSendViewDistance())); // Spigot // Paper - replace old player chunk management -+ entityplayer1.connection.send(new ClientboundSetSimulationDistancePacket(worldserver1.getWorld().getSimulationDistance())); // Spigot // Paper - replace old player chunk management - entityplayer1.spawnIn(worldserver1); - entityplayer1.unsetRemoved(); - entityplayer1.connection.teleport(CraftLocation.toBukkit(entityplayer1.position(), worldserver1.getWorld(), entityplayer1.getYRot(), entityplayer1.getXRot())); -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 0276c32ef8323bcf82eb3400bb003a93b8a56de0..5988c0847af4e8f0094328e91f736f25d567db60 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -455,7 +455,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - this.sendBlockUpdated(blockposition, iblockdata1, iblockdata, i); - // Paper start - per player view distance - allow block updates for non-ticking chunks in player view distance - // if copied from above -- } else if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || ((ServerLevel)this).getChunkSource().chunkMap.playerChunkManager.broadcastMap.getObjectsInRange(io.papermc.paper.util.MCUtil.getCoordinateKey(blockposition)) != null)) { // Paper - replace old player chunk management -+ } else if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0)) { // Paper - replace old player chunk management - ((ServerLevel)this).getChunkSource().blockChanged(blockposition); - // Paper end - per player view distance - } -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 41754f6c8162df07e2b22f4ffcacd8b6158a864e..3da04db71d6f33b2f466c11e031e0a11c298379b 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -172,43 +172,6 @@ public class LevelChunk extends ChunkAccess { - - protected void onNeighbourChange(final long bitsetBefore, final long bitsetAfter) { - -- // Paper start - no-tick view distance -- ServerChunkCache chunkProviderServer = ((ServerLevel)this.level).getChunkSource(); -- net.minecraft.server.level.ChunkMap chunkMap = chunkProviderServer.chunkMap; -- // this code handles the addition of ticking tickets - the distance map handles the removal -- if (!areNeighboursLoaded(bitsetBefore, 2) && areNeighboursLoaded(bitsetAfter, 2)) { -- if (chunkMap.playerChunkManager.tickMap.getObjectsInRange(this.coordinateKey) != null) { // Paper - replace old player chunk loading system -- // now we're ready for entity ticking -- chunkProviderServer.mainThreadProcessor.execute(() -> { -- // double check that this condition still holds. -- if (LevelChunk.this.areNeighboursLoaded(2) && chunkMap.playerChunkManager.tickMap.getObjectsInRange(LevelChunk.this.coordinateKey) != null) { // Paper - replace old player chunk loading system -- chunkMap.playerChunkManager.onChunkPlayerTickReady(this.chunkPos.x, this.chunkPos.z); // Paper - replace old player chunk -- chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.PLAYER, LevelChunk.this.chunkPos, 31, LevelChunk.this.chunkPos); // 31 -> entity ticking, TODO check on update -- } -- }); -- } -- } -- -- // this code handles the chunk sending -- if (!areNeighboursLoaded(bitsetBefore, 1) && areNeighboursLoaded(bitsetAfter, 1)) { -- // Paper start - replace old player chunk loading system -- if (chunkMap.playerChunkManager.isChunkNearPlayers(this.chunkPos.x, this.chunkPos.z)) { -- // the post processing is expensive, so we don't want to run it unless we're actually near -- // a player. -- chunkProviderServer.mainThreadProcessor.execute(() -> { -- if (!LevelChunk.this.areNeighboursLoaded(1)) { -- return; -- } -- LevelChunk.this.postProcessGeneration(); -- if (!LevelChunk.this.areNeighboursLoaded(1)) { -- return; -- } -- chunkMap.playerChunkManager.onChunkSendReady(this.chunkPos.x, this.chunkPos.z); -- }); -- } -- // Paper end - replace old player chunk loading system -- } -- // Paper end - no-tick view distance - } - - public final boolean isAnyNeighborsLoaded() { -@@ -781,7 +744,6 @@ public class LevelChunk extends ChunkAccess { - // Paper - rewrite chunk system - move into separate callback - org.bukkit.Server server = this.level.getCraftServer(); - // Paper - rewrite chunk system - move into separate callback -- ((ServerLevel)this.level).getChunkSource().chunkMap.playerChunkManager.onChunkLoad(this.chunkPos.x, this.chunkPos.z); // Paper - rewrite player chunk management - if (server != null) { - /* - * If it's a new world, the first few chunks are generated inside -@@ -956,6 +918,7 @@ public class LevelChunk extends ChunkAccess { - BlockState iblockdata1 = Block.updateFromNeighbourShapes(iblockdata, this.level, blockposition); - - this.level.setBlock(blockposition, iblockdata1, 20); -+ if (iblockdata1 != iblockdata) this.level.chunkSource.blockChanged(blockposition); // Paper - replace player chunk loader - notify since we send before processing full updates - } - } - -@@ -975,7 +938,6 @@ public class LevelChunk extends ChunkAccess { - this.upgradeData.upgrade(this); - } finally { // Paper start - replace chunk loader system - this.isPostProcessingDone = true; -- this.level.getChunkSource().chunkMap.playerChunkManager.onChunkPostProcessing(this.chunkPos.x, this.chunkPos.z); - } - // Paper end - replace chunk loader system - } -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 49623627555cb2b18ea8f7e17d0f6c1db54c0be4..7c4d43096031a3c93d5f835922b19d5643005128 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1947,12 +1947,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { - // Spigot start - @Override - public int getViewDistance() { -- return getHandle().getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance(); // Paper - replace old player chunk management -+ return this.getHandle().playerChunkLoader.getAPIViewDistance(); // Paper - replace player chunk loader - } - - @Override - public int getSimulationDistance() { -- return getHandle().getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance(); // Paper - replace old player chunk management -+ return this.getHandle().playerChunkLoader.getAPITickDistance(); // Paper - replace player chunk loader - } - // Spigot end - // Paper start - view distance api -@@ -1986,12 +1986,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public int getSendViewDistance() { -- return getHandle().getChunkSource().chunkMap.playerChunkManager.getTargetSendDistance(); -+ return this.getHandle().playerChunkLoader.getAPISendViewDistance(); // Paper - replace player chunk loader - } - - @Override - public void setSendViewDistance(int viewDistance) { -- getHandle().getChunkSource().chunkMap.playerChunkManager.setSendDistance(viewDistance); -+ this.getHandle().chunkSource.chunkMap.setSendViewDistance(viewDistance); // Paper - replace player chunk loader - } - // Paper end - view distance api - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 2f35f954eb2dcdc2de54b54c47c139908438e0f0..976eadd8200b2f4811d57b3c7fbd68cff1333924 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -187,44 +187,22 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - // Paper start - implement view distances - @Override - public int getViewDistance() { -- net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -- io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -- if (data == null) { -- return chunkMap.playerChunkManager.getTargetNoTickViewDistance(); -- } -- return data.getTargetNoTickViewDistance(); -+ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPIViewDistance(this); - } - - @Override - public void setViewDistance(int viewDistance) { -- net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -- io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -- if (data == null) { -- throw new IllegalStateException("Player is not attached to world"); -- } -- -- data.setTargetNoTickViewDistance(viewDistance); -+ this.getHandle().setLoadViewDistance(viewDistance < 0 ? viewDistance : viewDistance + 1); - } - - @Override - public int getSimulationDistance() { -- net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -- io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -- if (data == null) { -- return chunkMap.playerChunkManager.getTargetTickViewDistance(); -- } -- return data.getTargetTickViewDistance(); -+ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPITickViewDistance(this); - } - - @Override - public void setSimulationDistance(int simulationDistance) { -- net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -- io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -- if (data == null) { -- throw new IllegalStateException("Player is not attached to world"); -- } -- -- data.setTargetTickViewDistance(simulationDistance); -+ this.getHandle().setTickViewDistance(simulationDistance); - } - - @Override -@@ -239,23 +217,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public int getSendViewDistance() { -- net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -- io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -- if (data == null) { -- return chunkMap.playerChunkManager.getTargetSendDistance(); -- } -- return data.getTargetSendViewDistance(); -+ return io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.getAPISendViewDistance(this); - } - - @Override - public void setSendViewDistance(int viewDistance) { -- net.minecraft.server.level.ChunkMap chunkMap = this.getHandle().getLevel().getChunkSource().chunkMap; -- io.papermc.paper.chunk.PlayerChunkLoader.PlayerLoaderData data = chunkMap.playerChunkManager.getData(this.getHandle()); -- if (data == null) { -- throw new IllegalStateException("Player is not attached to world"); -- } -- -- data.setTargetSendViewDistance(viewDistance); -+ this.getHandle().setSendViewDistance(viewDistance); - } - // Paper end - implement view distances - diff --git a/patches/server/0024-Configurable-fishing-time-ranges.patch b/patches/server/0022-Configurable-fishing-time-ranges.patch similarity index 100% rename from patches/server/0024-Configurable-fishing-time-ranges.patch rename to patches/server/0022-Configurable-fishing-time-ranges.patch diff --git a/patches/server/0026-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch b/patches/server/0023-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch similarity index 100% rename from patches/server/0026-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch rename to patches/server/0023-Allow-nerfed-mobs-to-jump-and-take-water-damage.patch diff --git a/patches/server/0023-Make-ChunkStatus.EMPTY-not-rely-on-the-main-thread-f.patch b/patches/server/0023-Make-ChunkStatus.EMPTY-not-rely-on-the-main-thread-f.patch deleted file mode 100644 index e5364a1587..0000000000 --- a/patches/server/0023-Make-ChunkStatus.EMPTY-not-rely-on-the-main-thread-f.patch +++ /dev/null @@ -1,397 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Thu, 16 Feb 2023 16:50:05 -0800 -Subject: [PATCH] Make ChunkStatus.EMPTY not rely on the main thread for - completion - -In order to do this, we need to push the POI consistency checks -to a later status. Since FULL is the only other status that -uses the main thread, it can go there. - -The consistency checks are only really for when a desync occurs, -and so that delaying the check only matters when the chunk data -has desync'd. As long as the desync is sorted before the -chunk is full loaded (i.e before setBlock can occur on -a chunk), it should not matter. - -This change is primarily due to behavioural changes -in the chunk task queue brought by region threading - -which is to split the queue into separate regions. As such, -it is required that in order for the sync load to complete -that the region owning the chunk drain and execute the task -while ticking. However, that is not always possible in -region threading. Thus, removing the main thread reliance allows -the chunk to progress without requiring a tick thread. -Specifically, this allows far sync loads (outside of a specific -regions bounds) to occur without issue - namely with structure -searching. - -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java -index fb42d776f15f735fb59e972e00e2b512c23a8387..300700477ee34bc22b31315825c0e40f61070cd5 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java -@@ -2,6 +2,8 @@ package io.papermc.paper.chunk.system.scheduling; - - import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; - import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; -+import com.mojang.logging.LogUtils; -+import io.papermc.paper.chunk.system.poi.PoiChunk; - import net.minecraft.server.level.ChunkMap; - import net.minecraft.server.level.ServerLevel; - import net.minecraft.world.level.chunk.ChunkAccess; -@@ -9,10 +11,13 @@ import net.minecraft.world.level.chunk.ChunkStatus; - import net.minecraft.world.level.chunk.ImposterProtoChunk; - import net.minecraft.world.level.chunk.LevelChunk; - import net.minecraft.world.level.chunk.ProtoChunk; -+import org.slf4j.Logger; - import java.lang.invoke.VarHandle; - - public final class ChunkFullTask extends ChunkProgressionTask implements Runnable { - -+ private static final Logger LOGGER = LogUtils.getClassLogger(); -+ - protected final NewChunkHolder chunkHolder; - protected final ChunkAccess fromChunk; - protected final PrioritisedExecutor.PrioritisedTask convertToFullTask; -@@ -35,6 +40,15 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl - // See Vanilla protoChunkToFullChunk for what this function should be doing - final LevelChunk chunk; - try { -+ // moved from the load from nbt stage into here -+ final PoiChunk poiChunk = this.chunkHolder.getPoiChunk(); -+ if (poiChunk == null) { -+ LOGGER.error("Expected poi chunk to be loaded with chunk for task " + this.toString()); -+ } else { -+ poiChunk.load(); -+ this.world.getPoiManager().checkConsistency(this.fromChunk); -+ } -+ - if (this.fromChunk instanceof ImposterProtoChunk wrappedFull) { - chunk = wrappedFull.getWrapped(); - } else { -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java -index be6f3f6a57668a9bd50d0ea5f2dd2335355b69d6..1f7c146ff0b2a835c818f49da6c1f1411f26aa39 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java -@@ -25,6 +25,7 @@ import org.slf4j.Logger; - import java.lang.invoke.VarHandle; - import java.util.Map; - import java.util.concurrent.atomic.AtomicInteger; -+import java.util.concurrent.atomic.AtomicLong; - import java.util.function.Consumer; - - public final class ChunkLoadTask extends ChunkProgressionTask { -@@ -34,9 +35,11 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - private final NewChunkHolder chunkHolder; - private final ChunkDataLoadTask loadTask; - -- private boolean cancelled; -+ private volatile boolean cancelled; - private NewChunkHolder.GenericDataLoadTaskCallback entityLoadTask; - private NewChunkHolder.GenericDataLoadTaskCallback poiLoadTask; -+ private GenericDataLoadTask.TaskResult loadResult; -+ private final AtomicInteger taskCountToComplete = new AtomicInteger(3); // one for poi, one for entity, and one for chunk data - - protected ChunkLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX, final int chunkZ, - final NewChunkHolder chunkHolder, final PrioritisedExecutor.Priority priority) { -@@ -44,10 +47,18 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - this.chunkHolder = chunkHolder; - this.loadTask = new ChunkDataLoadTask(scheduler, world, chunkX, chunkZ, priority); - this.loadTask.addCallback((final GenericDataLoadTask.TaskResult result) -> { -- ChunkLoadTask.this.complete(result == null ? null : result.left(), result == null ? null : result.right()); -+ ChunkLoadTask.this.loadResult = result; // must be before getAndDecrement -+ ChunkLoadTask.this.tryCompleteLoad(); - }); - } - -+ private void tryCompleteLoad() { -+ if (this.taskCountToComplete.decrementAndGet() == 0) { -+ final GenericDataLoadTask.TaskResult result = this.cancelled ? null : this.loadResult; // only after the getAndDecrement -+ ChunkLoadTask.this.complete(result == null ? null : result.left(), result == null ? null : result.right()); -+ } -+ } -+ - @Override - public ChunkStatus getTargetStatus() { - return ChunkStatus.EMPTY; -@@ -65,11 +76,8 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - final NewChunkHolder.GenericDataLoadTaskCallback entityLoadTask; - final NewChunkHolder.GenericDataLoadTaskCallback poiLoadTask; - -- final AtomicInteger count = new AtomicInteger(); - final Consumer> scheduleLoadTask = (final GenericDataLoadTask.TaskResult result) -> { -- if (count.decrementAndGet() == 0) { -- ChunkLoadTask.this.loadTask.schedule(false); -- } -+ ChunkLoadTask.this.tryCompleteLoad(); - }; - - // NOTE: it is IMPOSSIBLE for getOrLoadEntityData/getOrLoadPoiData to complete synchronously, because -@@ -85,16 +93,16 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - } - if (!this.chunkHolder.isEntityChunkNBTLoaded()) { - entityLoadTask = this.chunkHolder.getOrLoadEntityData((Consumer)scheduleLoadTask); -- count.setPlain(count.getPlain() + 1); - } else { - entityLoadTask = null; -+ this.taskCountToComplete.getAndDecrement(); // we know the chunk load is not done here, as it is not scheduled - } - - if (!this.chunkHolder.isPoiChunkLoaded()) { - poiLoadTask = this.chunkHolder.getOrLoadPoiData((Consumer)scheduleLoadTask); -- count.setPlain(count.getPlain() + 1); - } else { - poiLoadTask = null; -+ this.taskCountToComplete.getAndDecrement(); // we know the chunk load is not done here, as it is not scheduled - } - - this.entityLoadTask = entityLoadTask; -@@ -107,14 +115,11 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - entityLoadTask.schedule(); - } - -- if (poiLoadTask != null) { -+ if (poiLoadTask != null) { - poiLoadTask.schedule(); - } - -- if (entityLoadTask == null && poiLoadTask == null) { -- // no need to wait on those, we can schedule now -- this.loadTask.schedule(false); -- } -+ this.loadTask.schedule(false); - } - - @Override -@@ -129,15 +134,20 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - - /* - Note: The entityLoadTask/poiLoadTask do not complete when cancelled, -- but this is fine because if they are successfully cancelled then -- we will successfully cancel the load task, which will complete when cancelled -+ so we need to manually try to complete in those cases -+ It is also important to note that we set the cancelled field first, just in case -+ the chunk load task attempts to complete with a non-null value - */ - - if (this.entityLoadTask != null) { -- this.entityLoadTask.cancel(); -+ if (this.entityLoadTask.cancel()) { -+ this.tryCompleteLoad(); -+ } - } - if (this.poiLoadTask != null) { -- this.poiLoadTask.cancel(); -+ if (this.poiLoadTask.cancel()) { -+ this.tryCompleteLoad(); -+ } - } - this.loadTask.cancel(); - } -@@ -249,7 +259,7 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - } - } - -- public final class ChunkDataLoadTask extends CallbackDataLoadTask { -+ public static final class ChunkDataLoadTask extends CallbackDataLoadTask { - protected ChunkDataLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX, - final int chunkZ, final PrioritisedExecutor.Priority priority) { - super(scheduler, world, chunkX, chunkZ, RegionFileIOThread.RegionFileType.CHUNK_DATA, priority); -@@ -262,7 +272,7 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - - @Override - protected boolean hasOnMain() { -- return true; -+ return false; - } - - @Override -@@ -272,35 +282,30 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - - @Override - protected PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final PrioritisedExecutor.Priority priority) { -- return this.scheduler.createChunkTask(this.chunkX, this.chunkZ, run, priority); -+ throw new UnsupportedOperationException(); - } - - @Override -- protected TaskResult completeOnMainOffMain(final ChunkSerializer.InProgressChunkHolder data, final Throwable throwable) { -- if (data != null) { -- return null; -- } -- -- final PoiChunk poiChunk = ChunkLoadTask.this.chunkHolder.getPoiChunk(); -- if (poiChunk == null) { -- LOGGER.error("Expected poi chunk to be loaded with chunk for task " + this.toString()); -- } else if (!poiChunk.isLoaded()) { -- // need to call poiChunk.load() on main -- return null; -- } -+ protected TaskResult completeOnMainOffMain(final ChunkAccess data, final Throwable throwable) { -+ throw new UnsupportedOperationException(); -+ } - -- return new TaskResult<>(this.getEmptyChunk(), null); -+ private ProtoChunk getEmptyChunk() { -+ return new ProtoChunk( -+ new ChunkPos(this.chunkX, this.chunkZ), UpgradeData.EMPTY, this.world, -+ this.world.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData)null -+ ); - } - - @Override -- protected TaskResult runOffMain(final CompoundTag data, final Throwable throwable) { -+ protected TaskResult runOffMain(final CompoundTag data, final Throwable throwable) { - if (throwable != null) { - LOGGER.error("Failed to load chunk data for task: " + this.toString() + ", chunk data will be lost", throwable); -- return new TaskResult<>(null, null); -+ return new TaskResult<>(this.getEmptyChunk(), null); - } - - if (data == null) { -- return new TaskResult<>(null, null); -+ return new TaskResult<>(this.getEmptyChunk(), null); - } - - // need to convert data, and then deserialize it -@@ -319,53 +324,18 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - this.world, chunkMap.getPoiManager(), chunkPos, converted, true - ); - -- return new TaskResult<>(chunkHolder, null); -+ return new TaskResult<>(chunkHolder.protoChunk, null); - } catch (final ThreadDeath death) { - throw death; - } catch (final Throwable thr2) { - LOGGER.error("Failed to parse chunk data for task: " + this.toString() + ", chunk data will be lost", thr2); -- return new TaskResult<>(null, thr2); -+ return new TaskResult<>(this.getEmptyChunk(), null); - } - } - -- private ProtoChunk getEmptyChunk() { -- return new ProtoChunk( -- new ChunkPos(this.chunkX, this.chunkZ), UpgradeData.EMPTY, this.world, -- this.world.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData)null -- ); -- } -- - @Override -- protected TaskResult runOnMain(final ChunkSerializer.InProgressChunkHolder data, final Throwable throwable) { -- final PoiChunk poiChunk = ChunkLoadTask.this.chunkHolder.getPoiChunk(); -- if (poiChunk == null) { -- LOGGER.error("Expected poi chunk to be loaded with chunk for task " + this.toString()); -- } else { -- poiChunk.load(); -- } -- -- if (data == null || data.protoChunk == null) { -- // throwable could be non-null, but the off-main task will print its exceptions - so we don't need to care, -- // it's handled already -- -- return new TaskResult<>(this.getEmptyChunk(), null); -- } -- -- // have tasks to run (at this point, it's just the POI consistency checking) -- try { -- if (data.tasks != null) { -- for (int i = 0, len = data.tasks.size(); i < len; ++i) { -- data.tasks.poll().run(); -- } -- } -- -- return new TaskResult<>(data.protoChunk, null); -- } catch (final ThreadDeath death) { -- throw death; -- } catch (final Throwable thr2) { -- LOGGER.error("Failed to parse main tasks for task " + this.toString() + ", chunk data will be lost", thr2); -- return new TaskResult<>(this.getEmptyChunk(), null); -- } -+ protected TaskResult runOnMain(final ChunkAccess data, final Throwable throwable) { -+ throw new UnsupportedOperationException(); - } - } - -diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -index f10ba4211cbdcc4f4ce3585c7cb3f80185e13b73..6f2c7baea0d1ac7813c7b85e1f5558573745762c 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -@@ -310,6 +310,17 @@ public class PoiManager extends SectionStorage { - } - } - } -+ -+ public void checkConsistency(net.minecraft.world.level.chunk.ChunkAccess chunk) { -+ int chunkX = chunk.getPos().x; -+ int chunkZ = chunk.getPos().z; -+ int minY = io.papermc.paper.util.WorldUtil.getMinSection(chunk); -+ int maxY = io.papermc.paper.util.WorldUtil.getMaxSection(chunk); -+ LevelChunkSection[] sections = chunk.getSections(); -+ for (int section = minY; section <= maxY; ++section) { -+ this.checkConsistencyWithBlocks(SectionPos.of(chunkX, section, chunkZ), sections[section - minY]); -+ } -+ } - // Paper end - rewrite chunk system - - public void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection chunkSection) { -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 55da32077d1db81ba197da0be5896da694f4bfa9..a7ee469bb2880a78540b79ae691ea449dfe22ce4 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -98,13 +98,11 @@ public class ChunkSerializer { - public static final class InProgressChunkHolder { - - public final ProtoChunk protoChunk; -- public final java.util.ArrayDeque tasks; - - public CompoundTag poiData; - -- public InProgressChunkHolder(final ProtoChunk protoChunk, final java.util.ArrayDeque tasks) { -+ public InProgressChunkHolder(final ProtoChunk protoChunk) { - this.protoChunk = protoChunk; -- this.tasks = tasks; - } - } - // Paper end -@@ -112,12 +110,10 @@ public class ChunkSerializer { - public static ProtoChunk read(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt) { - // Paper start - add variant for async calls - InProgressChunkHolder holder = loadChunk(world, poiStorage, chunkPos, nbt, true); -- holder.tasks.forEach(Runnable::run); - return holder.protoChunk; - } - - public static InProgressChunkHolder loadChunk(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt, boolean distinguish) { -- java.util.ArrayDeque tasksToExecuteOnMain = new java.util.ArrayDeque<>(); - // Paper end - ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); - -@@ -184,9 +180,7 @@ public class ChunkSerializer { - achunksection[k] = chunksection; - SectionPos sectionposition = SectionPos.of(chunkPos, b0); - -- tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main -- poiStorage.checkConsistencyWithBlocks(sectionposition, chunksection); -- }); // Paper - delay this task since we're executing off-main -+ // Paper - rewrite chunk system - moved to final load stage - } - - boolean flag3 = nbttagcompound1.contains("BlockLight", 7); -@@ -332,7 +326,7 @@ public class ChunkSerializer { - } - - if (chunkstatus_type == ChunkStatus.ChunkType.LEVELCHUNK) { -- return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object1, false), tasksToExecuteOnMain); // Paper - Async chunk loading -+ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object1, false)); // Paper - Async chunk loading - } else { - ProtoChunk protochunk1 = (ProtoChunk) object1; - -@@ -360,7 +354,7 @@ public class ChunkSerializer { - protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound5.getLongArray(s1), ((ChunkAccess) object1).getMinBuildHeight())); - } - -- return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading -+ return new InProgressChunkHolder(protochunk1); // Paper - Async chunk loading - } - } - diff --git a/patches/server/0028-Add-configurable-despawn-distances-for-living-entiti.patch b/patches/server/0024-Add-configurable-despawn-distances-for-living-entiti.patch similarity index 100% rename from patches/server/0028-Add-configurable-despawn-distances-for-living-entiti.patch rename to patches/server/0024-Add-configurable-despawn-distances-for-living-entiti.patch diff --git a/patches/server/0030-Allow-for-toggling-of-spawn-chunks.patch b/patches/server/0025-Allow-for-toggling-of-spawn-chunks.patch similarity index 100% rename from patches/server/0030-Allow-for-toggling-of-spawn-chunks.patch rename to patches/server/0025-Allow-for-toggling-of-spawn-chunks.patch diff --git a/patches/server/0025-Increase-parallelism-for-neighbour-writing-chunk-sta.patch b/patches/server/0025-Increase-parallelism-for-neighbour-writing-chunk-sta.patch deleted file mode 100644 index df5bbc9328..0000000000 --- a/patches/server/0025-Increase-parallelism-for-neighbour-writing-chunk-sta.patch +++ /dev/null @@ -1,999 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 26 Feb 2023 23:42:29 -0800 -Subject: [PATCH] Increase parallelism for neighbour writing chunk statuses - -Namely, everything after FEATURES. By creating a dependency -chain indicating what chunks are in use, we can safely -schedule completely independent tasks in parallel. This -will allow the chunk system to scale beyond 10 threads -per world. - -diff --git a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -index cf7610b3396d03bf79a899d5d9cfc6debb5b90be..48bfee5b9db501fcdba4ddb1e4bff2718956a680 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -+++ b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -@@ -286,7 +286,92 @@ public class RegionizedPlayerChunkLoader { - } - } - -- return chunks.toLongArray(); -+ // to increase generation parallelism, we want to space the chunks out so that they are not nearby when generating -+ // this also means we are minimising locality -+ // but, we need to maintain sorted order by manhatten distance -+ -+ // first, build a map of manhatten distance -> chunks -+ final java.util.List byDistance = new java.util.ArrayList<>(); -+ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator = chunks.iterator(); iterator.hasNext();) { -+ final long chunkKey = iterator.nextLong(); -+ -+ final int chunkX = CoordinateUtils.getChunkX(chunkKey); -+ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey); -+ -+ final int dist = Math.abs(chunkX) + Math.abs(chunkZ); -+ if (dist == byDistance.size()) { -+ final LongArrayList list = new LongArrayList(); -+ list.add(chunkKey); -+ byDistance.add(list); -+ continue; -+ } -+ -+ byDistance.get(dist).add(chunkKey); -+ } -+ -+ // per distance we transform the chunk list so that each element is maximally spaced out from each other -+ for (int i = 0, len = byDistance.size(); i < len; ++i) { -+ final LongArrayList notAdded = byDistance.get(i).clone(); -+ final LongArrayList added = new LongArrayList(); -+ -+ while (!notAdded.isEmpty()) { -+ if (added.isEmpty()) { -+ added.add(notAdded.removeLong(notAdded.size() - 1)); -+ continue; -+ } -+ -+ long maxChunk = -1L; -+ int maxDist = 0; -+ -+ // select the chunk from the not yet added set that has the largest minimum distance from -+ // the current set of added chunks -+ -+ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator = notAdded.iterator(); iterator.hasNext();) { -+ final long chunkKey = iterator.nextLong(); -+ final int chunkX = CoordinateUtils.getChunkX(chunkKey); -+ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey); -+ -+ int minDist = Integer.MAX_VALUE; -+ -+ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator2 = added.iterator(); iterator2.hasNext();) { -+ final long addedKey = iterator2.nextLong(); -+ final int addedX = CoordinateUtils.getChunkX(addedKey); -+ final int addedZ = CoordinateUtils.getChunkZ(addedKey); -+ -+ // here we use square distance because chunk generation uses neighbours in a square radius -+ final int dist = Math.max(Math.abs(addedX - chunkX), Math.abs(addedZ - chunkZ)); -+ -+ if (dist < minDist) { -+ minDist = dist; -+ } -+ } -+ -+ if (minDist > maxDist) { -+ maxDist = minDist; -+ maxChunk = chunkKey; -+ } -+ } -+ -+ // move the selected chunk from the not added set to the added set -+ -+ if (!notAdded.rem(maxChunk)) { -+ throw new IllegalStateException(); -+ } -+ -+ added.add(maxChunk); -+ } -+ -+ byDistance.set(i, added); -+ } -+ -+ // now, rebuild the list so that it still maintains manhatten distance order -+ final LongArrayList ret = new LongArrayList(chunks.size()); -+ -+ for (final LongArrayList dist : byDistance) { -+ ret.addAll(dist); -+ } -+ -+ return ret.toLongArray(); - } - - public static final class PlayerChunkLoaderData { -diff --git a/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java b/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java -index 0b7a2b0ead4f3bc07bfd9a38c2b7cf024bd140c6..36e93fefdfbebddce4c153974c7cd81af3cb92e9 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java -+++ b/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java -@@ -4,7 +4,6 @@ import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; - import ca.spottedleaf.starlight.common.light.BlockStarLightEngine; - import ca.spottedleaf.starlight.common.light.SkyStarLightEngine; - import ca.spottedleaf.starlight.common.light.StarLightInterface; --import io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler; - import io.papermc.paper.util.CoordinateUtils; - import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; - import it.unimi.dsi.fastutil.shorts.ShortCollection; -@@ -13,6 +12,7 @@ import net.minecraft.core.BlockPos; - import net.minecraft.core.SectionPos; - import net.minecraft.server.level.ServerLevel; - import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.chunk.ChunkStatus; - import java.util.ArrayList; - import java.util.HashSet; - import java.util.List; -@@ -201,7 +201,10 @@ public final class LightQueue { - this.chunkCoordinate = chunkCoordinate; - this.lightEngine = lightEngine; - this.queue = queue; -- this.task = queue.world.chunkTaskScheduler.lightExecutor.createTask(this, priority); -+ this.task = queue.world.chunkTaskScheduler.radiusAwareScheduler.createTask( -+ CoordinateUtils.getChunkX(chunkCoordinate), CoordinateUtils.getChunkZ(chunkCoordinate), -+ ChunkStatus.LIGHT.writeRadius, this, priority -+ ); - } - - public void schedule() { -@@ -230,23 +233,23 @@ public final class LightQueue { - - @Override - public void run() { -- final SkyStarLightEngine skyEngine = this.lightEngine.getSkyLightEngine(); -- final BlockStarLightEngine blockEngine = this.lightEngine.getBlockLightEngine(); -- try { -- synchronized (this.queue) { -- this.queue.chunkTasks.remove(this.chunkCoordinate); -- } -+ synchronized (this.queue) { -+ this.queue.chunkTasks.remove(this.chunkCoordinate); -+ } - -- boolean litChunk = false; -- if (this.lightTasks != null) { -- for (final BooleanSupplier run : this.lightTasks) { -- if (run.getAsBoolean()) { -- litChunk = true; -- break; -- } -+ boolean litChunk = false; -+ if (this.lightTasks != null) { -+ for (final BooleanSupplier run : this.lightTasks) { -+ if (run.getAsBoolean()) { -+ litChunk = true; -+ break; - } - } -+ } - -+ final SkyStarLightEngine skyEngine = this.lightEngine.getSkyLightEngine(); -+ final BlockStarLightEngine blockEngine = this.lightEngine.getBlockLightEngine(); -+ try { - final long coordinate = this.chunkCoordinate; - final int chunkX = CoordinateUtils.getChunkX(coordinate); - final int chunkZ = CoordinateUtils.getChunkZ(coordinate); -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -index ce26fdfa1afc74ba93d19157042f6c55778011e1..718c1dd7b52fb9a501d552fdbcb3f9ff79d127d8 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -@@ -1022,17 +1022,23 @@ public final class ChunkHolderManager { - } - - public Boolean tryDrainTicketUpdates() { -- final boolean acquired = this.ticketLock.tryLock(); -- try { -- if (!acquired) { -- return null; -- } -+ boolean ret = false; -+ for (;;) { -+ final boolean acquired = this.ticketLock.tryLock(); -+ try { -+ if (!acquired) { -+ return ret ? Boolean.TRUE : null; -+ } - -- return Boolean.valueOf(this.drainTicketUpdates()); -- } finally { -- if (acquired) { -- this.ticketLock.unlock(); -+ ret |= this.drainTicketUpdates(); -+ } finally { -+ if (acquired) { -+ this.ticketLock.unlock(); -+ } - } -+ if (this.delayedTicketUpdates.isEmpty()) { -+ return Boolean.valueOf(ret); -+ } // else: try to re-acquire - } - } - -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java -index 84d6af5c28cd0e81d50701bebe122f462720fbf8..d2bb266a5ed344507058778a94a8a4dcac61ba17 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java -@@ -2,9 +2,9 @@ package io.papermc.paper.chunk.system.scheduling; - - import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; - import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedThreadPool; --import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedThreadedTaskQueue; - import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; - import com.mojang.logging.LogUtils; -+import io.papermc.paper.chunk.system.scheduling.queue.RadiusAwarePrioritisedExecutor; - import io.papermc.paper.configuration.GlobalConfiguration; - import io.papermc.paper.util.CoordinateUtils; - import io.papermc.paper.util.TickThread; -@@ -21,7 +21,6 @@ import net.minecraft.world.level.ChunkPos; - import net.minecraft.world.level.chunk.ChunkAccess; - import net.minecraft.world.level.chunk.ChunkStatus; - import net.minecraft.world.level.chunk.LevelChunk; --import org.bukkit.Bukkit; - import org.slf4j.Logger; - import java.io.File; - import java.util.ArrayDeque; -@@ -34,7 +33,6 @@ import java.util.Objects; - import java.util.concurrent.atomic.AtomicBoolean; - import java.util.concurrent.atomic.AtomicLong; - import java.util.concurrent.locks.ReentrantLock; --import java.util.function.BooleanSupplier; - import java.util.function.Consumer; - - public final class ChunkTaskScheduler { -@@ -108,9 +106,9 @@ public final class ChunkTaskScheduler { - - public final ServerLevel world; - public final PrioritisedThreadPool workers; -- public final PrioritisedThreadPool.PrioritisedPoolExecutor lightExecutor; -- public final PrioritisedThreadPool.PrioritisedPoolExecutor genExecutor; -+ public final RadiusAwarePrioritisedExecutor radiusAwareScheduler; - public final PrioritisedThreadPool.PrioritisedPoolExecutor parallelGenExecutor; -+ private final PrioritisedThreadPool.PrioritisedPoolExecutor radiusAwareGenExecutor; - public final PrioritisedThreadPool.PrioritisedPoolExecutor loadExecutor; - - private final PrioritisedThreadedTaskQueue mainThreadExecutor = new PrioritisedThreadedTaskQueue(); -@@ -191,12 +189,11 @@ public final class ChunkTaskScheduler { - this.workers = workers; - - final String worldName = world.getWorld().getName(); -- this.genExecutor = workers.createExecutor("Chunk single-threaded generation executor for world '" + worldName + "'", 1); -- // same as genExecutor, as there are race conditions between updating blocks in FEATURE status while lighting chunks -- this.lightExecutor = this.genExecutor; -- this.parallelGenExecutor = newChunkSystemGenParallelism <= 1 ? this.genExecutor -- : workers.createExecutor("Chunk parallel generation executor for world '" + worldName + "'", newChunkSystemGenParallelism); -+ this.parallelGenExecutor = workers.createExecutor("Chunk parallel generation executor for world '" + worldName + "'", Math.max(1, newChunkSystemGenParallelism)); -+ this.radiusAwareGenExecutor = -+ newChunkSystemGenParallelism <= 1 ? this.parallelGenExecutor : workers.createExecutor("Chunk radius aware generator for world '" + worldName + "'", newChunkSystemGenParallelism); - this.loadExecutor = workers.createExecutor("Chunk load executor for world '" + worldName + "'", newChunkSystemLoadParallelism); -+ this.radiusAwareScheduler = new RadiusAwarePrioritisedExecutor(this.radiusAwareGenExecutor, Math.max(1, newChunkSystemGenParallelism)); - this.chunkHolderManager = new ChunkHolderManager(world, this); - } - -@@ -688,16 +685,14 @@ public final class ChunkTaskScheduler { - } - - public boolean halt(final boolean sync, final long maxWaitNS) { -- this.lightExecutor.halt(); -- this.genExecutor.halt(); -+ this.radiusAwareGenExecutor.halt(); - this.parallelGenExecutor.halt(); - this.loadExecutor.halt(); - final long time = System.nanoTime(); - if (sync) { - for (long failures = 9L;; failures = ConcurrentUtil.linearLongBackoff(failures, 500_000L, 50_000_000L)) { - if ( -- !this.lightExecutor.isActive() && -- !this.genExecutor.isActive() && -+ !this.radiusAwareGenExecutor.isActive() && - !this.parallelGenExecutor.isActive() && - !this.loadExecutor.isActive() - ) { -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java -index 73ce0909bd89244835a0d0f2030a25871461f1e0..ecc366a4176b2efadc46aa91aa21621f0fc6abe9 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java -@@ -39,8 +39,11 @@ public final class ChunkUpgradeGenericStatusTask extends ChunkProgressionTask im - this.fromStatus = chunk.getStatus(); - this.toStatus = toStatus; - this.neighbours = neighbours; -- this.generateTask = (this.toStatus.isParallelCapable ? this.scheduler.parallelGenExecutor : this.scheduler.genExecutor) -- .createTask(this, priority); -+ if (this.toStatus.isParallelCapable) { -+ this.generateTask = this.scheduler.parallelGenExecutor.createTask(this, priority); -+ } else { -+ this.generateTask = this.scheduler.radiusAwareScheduler.createTask(chunkX, chunkZ, this.toStatus.writeRadius, this, priority); -+ } - } - - @Override -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/queue/RadiusAwarePrioritisedExecutor.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/queue/RadiusAwarePrioritisedExecutor.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3272f73013ea7d4efdd0ae2903925cc543be7075 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/queue/RadiusAwarePrioritisedExecutor.java -@@ -0,0 +1,668 @@ -+package io.papermc.paper.chunk.system.scheduling.queue; -+ -+import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; -+import io.papermc.paper.util.CoordinateUtils; -+import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; -+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -+import java.util.ArrayList; -+import java.util.Comparator; -+import java.util.List; -+import java.util.PriorityQueue; -+ -+public class RadiusAwarePrioritisedExecutor { -+ -+ private static final Comparator DEPENDENCY_NODE_COMPARATOR = (final DependencyNode t1, final DependencyNode t2) -> { -+ return Long.compare(t1.id, t2.id); -+ }; -+ -+ private final DependencyTree[] queues = new DependencyTree[PrioritisedExecutor.Priority.TOTAL_SCHEDULABLE_PRIORITIES]; -+ private static final int NO_TASKS_QUEUED = -1; -+ private int selectedQueue = NO_TASKS_QUEUED; -+ private boolean canQueueTasks = true; -+ -+ public RadiusAwarePrioritisedExecutor(final PrioritisedExecutor executor, final int maxToSchedule) { -+ for (int i = 0; i < this.queues.length; ++i) { -+ this.queues[i] = new DependencyTree(this, executor, maxToSchedule, i); -+ } -+ } -+ -+ private boolean canQueueTasks() { -+ return this.canQueueTasks; -+ } -+ -+ private List treeFinished() { -+ this.canQueueTasks = true; -+ for (int priority = 0; priority < this.queues.length; ++priority) { -+ final DependencyTree queue = this.queues[priority]; -+ if (queue.hasWaitingTasks()) { -+ final List ret = queue.tryPushTasks(); -+ -+ if (ret == null || ret.isEmpty()) { -+ // this happens when the tasks in the wait queue were purged -+ // in this case, the queue was actually empty, we just had to purge it -+ // if we set the selected queue without scheduling any tasks, the queue will never be unselected -+ // as that requires a scheduled task completing... -+ continue; -+ } -+ -+ this.selectedQueue = priority; -+ return ret; -+ } -+ } -+ -+ this.selectedQueue = NO_TASKS_QUEUED; -+ -+ return null; -+ } -+ -+ private List queue(final Task task, final PrioritisedExecutor.Priority priority) { -+ final int priorityId = priority.priority; -+ final DependencyTree queue = this.queues[priorityId]; -+ -+ final DependencyNode node = new DependencyNode(task, queue); -+ -+ if (task.dependencyNode != null) { -+ throw new IllegalStateException(); -+ } -+ task.dependencyNode = node; -+ -+ queue.pushNode(node); -+ -+ if (this.selectedQueue == NO_TASKS_QUEUED) { -+ this.canQueueTasks = true; -+ this.selectedQueue = priorityId; -+ return queue.tryPushTasks(); -+ } -+ -+ if (!this.canQueueTasks) { -+ return null; -+ } -+ -+ if (PrioritisedExecutor.Priority.isHigherPriority(priorityId, this.selectedQueue)) { -+ // prevent the lower priority tree from queueing more tasks -+ this.canQueueTasks = false; -+ return null; -+ } -+ -+ // priorityId != selectedQueue: lower priority, don't care - treeFinished will pick it up -+ return priorityId == this.selectedQueue ? queue.tryPushTasks() : null; -+ } -+ -+ public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius, -+ final Runnable run, final PrioritisedExecutor.Priority priority) { -+ if (radius < 0) { -+ throw new IllegalArgumentException("Radius must be > 0: " + radius); -+ } -+ return new Task(this, chunkX, chunkZ, radius, run, priority); -+ } -+ -+ public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius, -+ final Runnable run) { -+ return this.createTask(chunkX, chunkZ, radius, run, PrioritisedExecutor.Priority.NORMAL); -+ } -+ -+ public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius, -+ final Runnable run, final PrioritisedExecutor.Priority priority) { -+ final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run, priority); -+ -+ ret.queue(); -+ -+ return ret; -+ } -+ -+ public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius, -+ final Runnable run) { -+ final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run); -+ -+ ret.queue(); -+ -+ return ret; -+ } -+ -+ public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run, final PrioritisedExecutor.Priority priority) { -+ return new Task(this, 0, 0, -1, run, priority); -+ } -+ -+ public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run) { -+ return this.createInfiniteRadiusTask(run, PrioritisedExecutor.Priority.NORMAL); -+ } -+ -+ public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run, final PrioritisedExecutor.Priority priority) { -+ final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, priority); -+ -+ ret.queue(); -+ -+ return ret; -+ } -+ -+ public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run) { -+ final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, PrioritisedExecutor.Priority.NORMAL); -+ -+ ret.queue(); -+ -+ return ret; -+ } -+ -+ // all accesses must be synchronised by the radius aware object -+ private static final class DependencyTree { -+ -+ private final RadiusAwarePrioritisedExecutor scheduler; -+ private final PrioritisedExecutor executor; -+ private final int maxToSchedule; -+ private final int treeIndex; -+ -+ private int currentlyExecuting; -+ private long idGenerator; -+ -+ private final PriorityQueue awaiting = new PriorityQueue<>(DEPENDENCY_NODE_COMPARATOR); -+ -+ private final PriorityQueue infiniteRadius = new PriorityQueue<>(DEPENDENCY_NODE_COMPARATOR); -+ private boolean isInfiniteRadiusScheduled; -+ -+ private final Long2ReferenceOpenHashMap nodeByPosition = new Long2ReferenceOpenHashMap<>(); -+ -+ public DependencyTree(final RadiusAwarePrioritisedExecutor scheduler, final PrioritisedExecutor executor, -+ final int maxToSchedule, final int treeIndex) { -+ this.scheduler = scheduler; -+ this.executor = executor; -+ this.maxToSchedule = maxToSchedule; -+ this.treeIndex = treeIndex; -+ } -+ -+ public boolean hasWaitingTasks() { -+ return !this.awaiting.isEmpty() || !this.infiniteRadius.isEmpty(); -+ } -+ -+ private long nextId() { -+ return this.idGenerator++; -+ } -+ -+ private boolean isExecutingAnyTasks() { -+ return this.currentlyExecuting != 0; -+ } -+ -+ private void pushNode(final DependencyNode node) { -+ if (!node.task.isFiniteRadius()) { -+ this.infiniteRadius.add(node); -+ return; -+ } -+ -+ // set up dependency for node -+ final Task task = node.task; -+ -+ final int centerX = task.chunkX; -+ final int centerZ = task.chunkZ; -+ final int radius = task.radius; -+ -+ final int minX = centerX - radius; -+ final int maxX = centerX + radius; -+ -+ final int minZ = centerZ - radius; -+ final int maxZ = centerZ + radius; -+ -+ ReferenceOpenHashSet parents = null; -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ for (int currX = minX; currX <= maxX; ++currX) { -+ final DependencyNode dependency = this.nodeByPosition.put(CoordinateUtils.getChunkKey(currX, currZ), node); -+ if (dependency != null) { -+ if (parents == null) { -+ parents = new ReferenceOpenHashSet<>(); -+ } -+ if (parents.add(dependency)) { -+ // added a dependency, so we need to add as a child to the dependency -+ if (dependency.children == null) { -+ dependency.children = new ArrayList<>(); -+ } -+ dependency.children.add(node); -+ } -+ } -+ } -+ } -+ -+ if (parents == null) { -+ // no dependencies, add straight to awaiting -+ this.awaiting.add(node); -+ } else { -+ node.parents = parents; -+ // we will be added to awaiting once we have no parents -+ } -+ } -+ -+ // called only when a node is returned after being executed -+ private List returnNode(final DependencyNode node) { -+ final Task task = node.task; -+ -+ // now that the task is completed, we can push its children to the awaiting queue -+ this.pushChildren(node); -+ -+ if (task.isFiniteRadius()) { -+ // remove from dependency map -+ this.removeNodeFromMap(node); -+ } else { -+ // mark as no longer executing infinite radius -+ if (!this.isInfiniteRadiusScheduled) { -+ throw new IllegalStateException(); -+ } -+ this.isInfiniteRadiusScheduled = false; -+ } -+ -+ // decrement executing count, we are done executing this task -+ --this.currentlyExecuting; -+ -+ if (this.currentlyExecuting == 0) { -+ return this.scheduler.treeFinished(); -+ } -+ -+ return this.scheduler.canQueueTasks() ? this.tryPushTasks() : null; -+ } -+ -+ private List tryPushTasks() { -+ // tasks are not queued, but only created here - we do hold the lock for the map -+ List ret = null; -+ PrioritisedExecutor.PrioritisedTask pushedTask; -+ while ((pushedTask = this.tryPushTask()) != null) { -+ if (ret == null) { -+ ret = new ArrayList<>(); -+ } -+ ret.add(pushedTask); -+ } -+ -+ return ret; -+ } -+ -+ private void removeNodeFromMap(final DependencyNode node) { -+ final Task task = node.task; -+ -+ final int centerX = task.chunkX; -+ final int centerZ = task.chunkZ; -+ final int radius = task.radius; -+ -+ final int minX = centerX - radius; -+ final int maxX = centerX + radius; -+ -+ final int minZ = centerZ - radius; -+ final int maxZ = centerZ + radius; -+ -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ for (int currX = minX; currX <= maxX; ++currX) { -+ this.nodeByPosition.remove(CoordinateUtils.getChunkKey(currX, currZ), node); -+ } -+ } -+ } -+ -+ private void pushChildren(final DependencyNode node) { -+ // add all the children that we can into awaiting -+ final List children = node.children; -+ if (children != null) { -+ for (int i = 0, len = children.size(); i < len; ++i) { -+ final DependencyNode child = children.get(i); -+ if (!child.parents.remove(node)) { -+ throw new IllegalStateException(); -+ } -+ if (child.parents.isEmpty()) { -+ // no more dependents, we can push to awaiting -+ child.parents = null; -+ // even if the child is purged, we need to push it so that its children will be pushed -+ this.awaiting.add(child); -+ } -+ } -+ } -+ } -+ -+ private DependencyNode pollAwaiting() { -+ final DependencyNode ret = this.awaiting.poll(); -+ if (ret == null) { -+ return ret; -+ } -+ -+ if (ret.parents != null) { -+ throw new IllegalStateException(); -+ } -+ -+ if (ret.purged) { -+ // need to manually remove from state here -+ this.pushChildren(ret); -+ this.removeNodeFromMap(ret); -+ } // else: delay children push until the task has finished -+ -+ return ret; -+ } -+ -+ private DependencyNode pollInfinite() { -+ return this.infiniteRadius.poll(); -+ } -+ -+ public PrioritisedExecutor.PrioritisedTask tryPushTask() { -+ if (this.currentlyExecuting >= this.maxToSchedule || this.isInfiniteRadiusScheduled) { -+ return null; -+ } -+ -+ DependencyNode firstInfinite; -+ while ((firstInfinite = this.infiniteRadius.peek()) != null && firstInfinite.purged) { -+ this.pollInfinite(); -+ } -+ -+ DependencyNode firstAwaiting; -+ while ((firstAwaiting = this.awaiting.peek()) != null && firstAwaiting.purged) { -+ this.pollAwaiting(); -+ } -+ -+ if (firstInfinite == null && firstAwaiting == null) { -+ return null; -+ } -+ -+ // firstAwaiting compared to firstInfinite -+ final int compare; -+ -+ if (firstAwaiting == null) { -+ // we choose first infinite, or infinite < awaiting -+ compare = 1; -+ } else if (firstInfinite == null) { -+ // we choose first awaiting, or awaiting < infinite -+ compare = -1; -+ } else { -+ compare = DEPENDENCY_NODE_COMPARATOR.compare(firstAwaiting, firstInfinite); -+ } -+ -+ if (compare >= 0) { -+ if (this.currentlyExecuting != 0) { -+ // don't queue infinite task while other tasks are executing in parallel -+ return null; -+ } -+ ++this.currentlyExecuting; -+ this.pollInfinite(); -+ this.isInfiniteRadiusScheduled = true; -+ return firstInfinite.task.pushTask(this.executor); -+ } else { -+ ++this.currentlyExecuting; -+ this.pollAwaiting(); -+ return firstAwaiting.task.pushTask(this.executor); -+ } -+ } -+ } -+ -+ private static final class DependencyNode { -+ -+ private final Task task; -+ private final DependencyTree tree; -+ -+ // dependency tree fields -+ // (must hold lock on the scheduler to use) -+ // null is the same as empty, we just use it so that we don't allocate the set unless we need to -+ private List children; -+ // null is the same as empty, indicating that this task is considered "awaiting" -+ private ReferenceOpenHashSet parents; -+ // false -> scheduled and not cancelled -+ // true -> scheduled but cancelled -+ private boolean purged; -+ private final long id; -+ -+ public DependencyNode(final Task task, final DependencyTree tree) { -+ this.task = task; -+ this.id = tree.nextId(); -+ this.tree = tree; -+ } -+ } -+ -+ private static final class Task implements PrioritisedExecutor.PrioritisedTask, Runnable { -+ -+ // task specific fields -+ private final RadiusAwarePrioritisedExecutor scheduler; -+ private final int chunkX; -+ private final int chunkZ; -+ private final int radius; -+ private Runnable run; -+ private PrioritisedExecutor.Priority priority; -+ -+ private DependencyNode dependencyNode; -+ private PrioritisedExecutor.PrioritisedTask queuedTask; -+ -+ private Task(final RadiusAwarePrioritisedExecutor scheduler, final int chunkX, final int chunkZ, final int radius, -+ final Runnable run, final PrioritisedExecutor.Priority priority) { -+ this.scheduler = scheduler; -+ this.chunkX = chunkX; -+ this.chunkZ = chunkZ; -+ this.radius = radius; -+ this.run = run; -+ this.priority = priority; -+ } -+ -+ private boolean isFiniteRadius() { -+ return this.radius >= 0; -+ } -+ -+ private PrioritisedExecutor.PrioritisedTask pushTask(final PrioritisedExecutor executor) { -+ return this.queuedTask = executor.createTask(this, this.priority); -+ } -+ -+ private void executeTask() { -+ final Runnable run = this.run; -+ this.run = null; -+ run.run(); -+ } -+ -+ private static void scheduleTasks(final List toSchedule) { -+ if (toSchedule != null) { -+ for (int i = 0, len = toSchedule.size(); i < len; ++i) { -+ toSchedule.get(i).queue(); -+ } -+ } -+ } -+ -+ private void returnNode() { -+ final List toSchedule; -+ synchronized (this.scheduler) { -+ final DependencyNode node = this.dependencyNode; -+ this.dependencyNode = null; -+ toSchedule = node.tree.returnNode(node); -+ } -+ -+ scheduleTasks(toSchedule); -+ } -+ -+ @Override -+ public void run() { -+ final Runnable run = this.run; -+ this.run = null; -+ try { -+ run.run(); -+ } finally { -+ this.returnNode(); -+ } -+ } -+ -+ @Override -+ public boolean queue() { -+ final List toSchedule; -+ synchronized (this.scheduler) { -+ if (this.queuedTask != null || this.dependencyNode != null || this.priority == PrioritisedExecutor.Priority.COMPLETING) { -+ return false; -+ } -+ -+ toSchedule = this.scheduler.queue(this, this.priority); -+ } -+ -+ scheduleTasks(toSchedule); -+ return true; -+ } -+ -+ @Override -+ public boolean cancel() { -+ final PrioritisedExecutor.PrioritisedTask task; -+ synchronized (this.scheduler) { -+ if ((task = this.queuedTask) == null) { -+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { -+ return false; -+ } -+ -+ this.priority = PrioritisedExecutor.Priority.COMPLETING; -+ if (this.dependencyNode != null) { -+ this.dependencyNode.purged = true; -+ this.dependencyNode = null; -+ } -+ -+ return true; -+ } -+ } -+ -+ if (task.cancel()) { -+ // must manually return the node -+ this.run = null; -+ this.returnNode(); -+ return true; -+ } -+ return false; -+ } -+ -+ @Override -+ public boolean execute() { -+ final PrioritisedExecutor.PrioritisedTask task; -+ synchronized (this.scheduler) { -+ if ((task = this.queuedTask) == null) { -+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { -+ return false; -+ } -+ -+ this.priority = PrioritisedExecutor.Priority.COMPLETING; -+ if (this.dependencyNode != null) { -+ this.dependencyNode.purged = true; -+ this.dependencyNode = null; -+ } -+ // fall through to execution logic -+ } -+ } -+ -+ if (task != null) { -+ // will run the return node logic automatically -+ return task.execute(); -+ } else { -+ // don't run node removal/insertion logic, we aren't actually removed from the dependency tree -+ this.executeTask(); -+ return true; -+ } -+ } -+ -+ @Override -+ public PrioritisedExecutor.Priority getPriority() { -+ final PrioritisedExecutor.PrioritisedTask task; -+ synchronized (this.scheduler) { -+ if ((task = this.queuedTask) == null) { -+ return this.priority; -+ } -+ } -+ -+ return task.getPriority(); -+ } -+ -+ @Override -+ public boolean setPriority(final PrioritisedExecutor.Priority priority) { -+ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { -+ throw new IllegalArgumentException("Invalid priority " + priority); -+ } -+ -+ final PrioritisedExecutor.PrioritisedTask task; -+ List toSchedule = null; -+ synchronized (this.scheduler) { -+ if ((task = this.queuedTask) == null) { -+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { -+ return false; -+ } -+ -+ if (this.priority == priority) { -+ return true; -+ } -+ -+ this.priority = priority; -+ if (this.dependencyNode != null) { -+ // need to re-insert node -+ this.dependencyNode.purged = true; -+ this.dependencyNode = null; -+ toSchedule = this.scheduler.queue(this, priority); -+ } -+ } -+ } -+ -+ if (task != null) { -+ return task.setPriority(priority); -+ } -+ -+ scheduleTasks(toSchedule); -+ -+ return true; -+ } -+ -+ @Override -+ public boolean raisePriority(final PrioritisedExecutor.Priority priority) { -+ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { -+ throw new IllegalArgumentException("Invalid priority " + priority); -+ } -+ -+ final PrioritisedExecutor.PrioritisedTask task; -+ List toSchedule = null; -+ synchronized (this.scheduler) { -+ if ((task = this.queuedTask) == null) { -+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { -+ return false; -+ } -+ -+ if (this.priority.isHigherOrEqualPriority(priority)) { -+ return true; -+ } -+ -+ this.priority = priority; -+ if (this.dependencyNode != null) { -+ // need to re-insert node -+ this.dependencyNode.purged = true; -+ this.dependencyNode = null; -+ toSchedule = this.scheduler.queue(this, priority); -+ } -+ } -+ } -+ -+ if (task != null) { -+ return task.raisePriority(priority); -+ } -+ -+ scheduleTasks(toSchedule); -+ -+ return true; -+ } -+ -+ @Override -+ public boolean lowerPriority(final PrioritisedExecutor.Priority priority) { -+ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) { -+ throw new IllegalArgumentException("Invalid priority " + priority); -+ } -+ -+ final PrioritisedExecutor.PrioritisedTask task; -+ List toSchedule = null; -+ synchronized (this.scheduler) { -+ if ((task = this.queuedTask) == null) { -+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) { -+ return false; -+ } -+ -+ if (this.priority.isLowerOrEqualPriority(priority)) { -+ return true; -+ } -+ -+ this.priority = priority; -+ if (this.dependencyNode != null) { -+ // need to re-insert node -+ this.dependencyNode.purged = true; -+ this.dependencyNode = null; -+ toSchedule = this.scheduler.queue(this, priority); -+ } -+ } -+ } -+ -+ if (task != null) { -+ return task.lowerPriority(priority); -+ } -+ -+ scheduleTasks(toSchedule); -+ -+ return true; -+ } -+ } -+} -diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -index c709e27a00d8617f9a3346f85bd88ce47baa9c76..b4be02ec4bb77059f79d3e4d6a6f1ee4843a01f9 100644 ---- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -+++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -@@ -94,7 +94,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - ++totalChunks; - } - -- this.chunkMap.level.chunkTaskScheduler.lightExecutor.queueRunnable(() -> { // Paper - rewrite chunk system -+ this.chunkMap.level.chunkTaskScheduler.radiusAwareScheduler.queueInfiniteRadiusTask(() -> { // Paper - rewrite chunk system - this.theLightEngine.relightChunks(chunks, (ChunkPos chunkPos) -> { - chunkLightCallback.accept(chunkPos); - ((java.util.concurrent.Executor)((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().mainThreadProcessor).execute(() -> { diff --git a/patches/server/0032-Drop-falling-block-and-tnt-entities-at-the-specified.patch b/patches/server/0026-Drop-falling-block-and-tnt-entities-at-the-specified.patch similarity index 100% rename from patches/server/0032-Drop-falling-block-and-tnt-entities-at-the-specified.patch rename to patches/server/0026-Drop-falling-block-and-tnt-entities-at-the-specified.patch diff --git a/patches/server/0027-Properly-cancel-chunk-load-tasks-that-were-not-sched.patch b/patches/server/0027-Properly-cancel-chunk-load-tasks-that-were-not-sched.patch deleted file mode 100644 index 3fd8ac049c..0000000000 --- a/patches/server/0027-Properly-cancel-chunk-load-tasks-that-were-not-sched.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 15 May 2023 12:24:17 -0700 -Subject: [PATCH] Properly cancel chunk load tasks that were not scheduled - -Since the chunk load task was not scheduled, the entity/poi load -task fields will not be set, but the task complete counter -will not be adjusted. Thus, the chunk load task will not complete. - -To resolve this, detect when the entity/poi tasks were not scheduled -and decrement the task complete counter in such cases. - -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java -index 1f7c146ff0b2a835c818f49da6c1f1411f26aa39..34dc2153e90a29bc9102d9497c3c53b5de15508e 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java -@@ -25,7 +25,6 @@ import org.slf4j.Logger; - import java.lang.invoke.VarHandle; - import java.util.Map; - import java.util.concurrent.atomic.AtomicInteger; --import java.util.concurrent.atomic.AtomicLong; - import java.util.function.Consumer; - - public final class ChunkLoadTask extends ChunkProgressionTask { -@@ -125,8 +124,12 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - @Override - public void cancel() { - // must be before load task access, so we can synchronise with the writes to the fields -+ final boolean scheduled; - this.scheduler.schedulingLock.lock(); - try { -+ // fix cancellation of chunk load task - must read field here, as it may be written later conucrrently - -+ // we need to know if we scheduled _before_ cancellation -+ scheduled = this.scheduled; - this.cancelled = true; - } finally { - this.scheduler.schedulingLock.unlock(); -@@ -139,15 +142,26 @@ public final class ChunkLoadTask extends ChunkProgressionTask { - the chunk load task attempts to complete with a non-null value - */ - -- if (this.entityLoadTask != null) { -- if (this.entityLoadTask.cancel()) { -- this.tryCompleteLoad(); -+ if (scheduled) { -+ // since we scheduled, we need to cancel the tasks -+ if (this.entityLoadTask != null) { -+ if (this.entityLoadTask.cancel()) { -+ this.tryCompleteLoad(); -+ } - } -- } -- if (this.poiLoadTask != null) { -- if (this.poiLoadTask.cancel()) { -- this.tryCompleteLoad(); -+ if (this.poiLoadTask != null) { -+ if (this.poiLoadTask.cancel()) { -+ this.tryCompleteLoad(); -+ } - } -+ } else { -+ // since nothing was scheduled, we need to decrement the task count here ourselves -+ -+ // for entity load task -+ this.tryCompleteLoad(); -+ -+ // for poi load task -+ this.tryCompleteLoad(); - } - this.loadTask.cancel(); - } diff --git a/patches/server/0033-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch b/patches/server/0027-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch similarity index 100% rename from patches/server/0033-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch rename to patches/server/0027-Show-Paper-in-client-crashes-server-lists-and-Mojang.patch diff --git a/patches/server/0034-Implement-Paper-VersionChecker.patch b/patches/server/0028-Implement-Paper-VersionChecker.patch similarity index 100% rename from patches/server/0034-Implement-Paper-VersionChecker.patch rename to patches/server/0028-Implement-Paper-VersionChecker.patch diff --git a/patches/server/0035-Add-version-history-to-version-command.patch b/patches/server/0029-Add-version-history-to-version-command.patch similarity index 100% rename from patches/server/0035-Add-version-history-to-version-command.patch rename to patches/server/0029-Add-version-history-to-version-command.patch diff --git a/patches/server/0029-Mark-POI-Entity-load-tasks-as-completed-before-relea.patch b/patches/server/0029-Mark-POI-Entity-load-tasks-as-completed-before-relea.patch deleted file mode 100644 index 2c6336128b..0000000000 --- a/patches/server/0029-Mark-POI-Entity-load-tasks-as-completed-before-relea.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 15 May 2023 11:34:28 -0700 -Subject: [PATCH] Mark POI/Entity load tasks as completed before releasing - scheduling lock - -It must be marked as completed during that lock hold since the -waiters field is set to null. Thus, any other thread attempting -a cancellation will fail to remove from waiters. Also, any -other thread attempting to cancel may set the completed field -to true which would cause accept() to fail as well. - -Completion was always designed to happen while holding the -scheduling lock to prevent these race conditions. The code -was originally set up to complete while not holding the -scheduling lock to avoid invoking callbacks while holding the -lock, however the access to the completion field was not -considered. - -Resolve this by marking the callback as completed during the -lock, but invoking the accept() function after releasing -the lock. This will prevent any cancellation attempts to be -blocked, and allow the current thread to complete the callback -without any issues. - -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -index 8013dd333e27aa5fd0beb431fa32491eec9f5246..efc9b7a304f10b6a23a36cffb0a4aaea6ab71129 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -@@ -156,6 +156,12 @@ public final class NewChunkHolder { - LOGGER.error("Unhandled entity data load exception, data data will be lost: ", result.right()); - } - -+ // Folia start - mark these tasks as completed before releasing the scheduling lock -+ for (final GenericDataLoadTaskCallback callback : waiters) { -+ callback.markCompleted(); -+ } -+ // Folia end - mark these tasks as completed before releasing the scheduling lock -+ - completeWaiters = waiters; - } else { - // cancelled -@@ -187,7 +193,7 @@ public final class NewChunkHolder { - // avoid holding the scheduling lock while completing - if (completeWaiters != null) { - for (final GenericDataLoadTaskCallback callback : completeWaiters) { -- callback.accept(result); -+ callback.acceptCompleted(result); // Folia - mark these tasks as completed before releasing the scheduling lock - } - } - -@@ -273,6 +279,12 @@ public final class NewChunkHolder { - LOGGER.error("Unhandled poi load exception, poi data will be lost: ", result.right()); - } - -+ // Folia start - mark these tasks as completed before releasing the scheduling lock -+ for (final GenericDataLoadTaskCallback callback : waiters) { -+ callback.markCompleted(); -+ } -+ // Folia end - mark these tasks as completed before releasing the scheduling lock -+ - completeWaiters = waiters; - } else { - // cancelled -@@ -304,7 +316,7 @@ public final class NewChunkHolder { - // avoid holding the scheduling lock while completing - if (completeWaiters != null) { - for (final GenericDataLoadTaskCallback callback : completeWaiters) { -- callback.accept(result); -+ callback.acceptCompleted(result); // Folia - mark these tasks as completed before releasing the scheduling lock - } - } - this.scheduler.schedulingLock.lock(); -@@ -357,7 +369,7 @@ public final class NewChunkHolder { - } - } - -- public static abstract class GenericDataLoadTaskCallback implements Cancellable, Consumer> { -+ public static abstract class GenericDataLoadTaskCallback implements Cancellable { // Folia - mark callbacks as completed before unlocking scheduling lock - - protected final Consumer> consumer; - protected final NewChunkHolder chunkHolder; -@@ -393,13 +405,23 @@ public final class NewChunkHolder { - return this.completed = true; - } - -- @Override -- public void accept(final GenericDataLoadTask.TaskResult result) { -+ // Folia start - mark callbacks as completed before unlocking scheduling lock -+ // must hold scheduling lock -+ void markCompleted() { -+ if (this.completed) { -+ throw new IllegalStateException("May not be completed here"); -+ } -+ this.completed = true; -+ } -+ // Folia end - mark callbacks as completed before unlocking scheduling lock -+ -+ // Folia - mark callbacks as completed before unlocking scheduling lock -+ void acceptCompleted(final GenericDataLoadTask.TaskResult result) { - if (result != null) { -- if (this.setCompleted()) { -+ if (this.completed) { // Folia - mark callbacks as completed before unlocking scheduling lock - this.consumer.accept(result); - } else { -- throw new IllegalStateException("Cannot be cancelled at this point"); -+ throw new IllegalStateException("Cannot be uncompleted at this point"); // Folia - mark callbacks as completed before unlocking scheduling lock - } - } else { - throw new NullPointerException("Result cannot be null (cancelled)"); diff --git a/patches/server/0036-Player-affects-spawning-API.patch b/patches/server/0030-Player-affects-spawning-API.patch similarity index 100% rename from patches/server/0036-Player-affects-spawning-API.patch rename to patches/server/0030-Player-affects-spawning-API.patch diff --git a/patches/server/0031-Cache-whether-region-files-do-not-exist.patch b/patches/server/0031-Cache-whether-region-files-do-not-exist.patch deleted file mode 100644 index 3a7c248487..0000000000 --- a/patches/server/0031-Cache-whether-region-files-do-not-exist.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Thu, 2 Mar 2023 23:19:04 -0800 -Subject: [PATCH] Cache whether region files do not exist - -The repeated I/O of creating the directory for the regionfile -or for checking if the file exists can be heavy in -when pushing chunk generation extremely hard - as each chunk gen -request may effectively go through to the I/O thread. - -diff --git a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java -index a08cde4eefe879adcee7c4118bc38f98c5097ed0..8a11e10b01fa012b2f98b1c193c53251e848f909 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java -+++ b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java -@@ -819,8 +819,14 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread { - return file.hasChunk(chunkPos) ? Boolean.TRUE : Boolean.FALSE; - }); - } else { -+ // first check if the region file for sure does not exist -+ if (taskController.doesRegionFileNotExist(chunkX, chunkZ)) { -+ return Boolean.FALSE; -+ } // else: it either exists or is not known, fall back to checking the loaded region file -+ - return taskController.computeForRegionFileIfLoaded(chunkX, chunkZ, (final RegionFile file) -> { - if (file == null) { // null if not loaded -+ // not sure at this point, let the I/O thread figure it out - return Boolean.TRUE; - } - -@@ -1116,6 +1122,10 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread { - return !this.tasks.isEmpty(); - } - -+ public boolean doesRegionFileNotExist(final int chunkX, final int chunkZ) { -+ return this.getCache().doesRegionFileNotExistNoIO(new ChunkPos(chunkX, chunkZ)); -+ } -+ - public T computeForRegionFile(final int chunkX, final int chunkZ, final boolean existingOnly, final Function function) { - final RegionFileStorage cache = this.getCache(); - final RegionFile regionFile; -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 18ef7025f7f4dc2a4aff85ca65ff5a2d35a1ef06..fe8bb0037bb7f317fc32ac34461f4eb3a1f397f2 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -24,6 +24,35 @@ public class RegionFileStorage implements AutoCloseable { - private final Path folder; - private final boolean sync; - -+ // Paper start - cache regionfile does not exist state -+ static final int MAX_NON_EXISTING_CACHE = 1024 * 64; -+ private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet(); -+ private synchronized boolean doesRegionFilePossiblyExist(long position) { -+ if (this.nonExistingRegionFiles.contains(position)) { -+ this.nonExistingRegionFiles.addAndMoveToFirst(position); -+ return false; -+ } -+ return true; -+ } -+ -+ private synchronized void createRegionFile(long position) { -+ this.nonExistingRegionFiles.remove(position); -+ } -+ -+ private synchronized void markNonExisting(long position) { -+ if (this.nonExistingRegionFiles.addAndMoveToFirst(position)) { -+ while (this.nonExistingRegionFiles.size() >= MAX_NON_EXISTING_CACHE) { -+ this.nonExistingRegionFiles.removeLastLong(); -+ } -+ } -+ } -+ -+ public synchronized boolean doesRegionFileNotExistNoIO(ChunkPos pos) { -+ long key = ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()); -+ return !this.doesRegionFilePossiblyExist(key); -+ } -+ // Paper end - cache regionfile does not exist state -+ - protected RegionFileStorage(Path directory, boolean dsync) { // Paper - protected constructor - this.folder = directory; - this.sync = dsync; -@@ -45,7 +74,7 @@ public class RegionFileStorage implements AutoCloseable { - } - public synchronized RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException { - // Paper end -- long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); -+ long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); final long regionPos = i; // Paper - OBFHELPER - RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i); - - if (regionfile != null) { -@@ -57,15 +86,27 @@ public class RegionFileStorage implements AutoCloseable { - // Paper end - return regionfile; - } else { -+ // Paper start - cache regionfile does not exist state -+ if (existingOnly && !this.doesRegionFilePossiblyExist(regionPos)) { -+ return null; -+ } -+ // Paper end - cache regionfile does not exist state - if (this.regionCache.size() >= 256) { - ((RegionFile) this.regionCache.removeLast()).close(); - } - -- FileUtil.createDirectoriesSafe(this.folder); -+ // Paper - only create directory if not existing only - moved down - Path path = this.folder; - int j = chunkcoordintpair.getRegionX(); - Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); -- if (existingOnly && !java.nio.file.Files.exists(path1)) return null; // CraftBukkit -+ if (existingOnly && !java.nio.file.Files.exists(path1)) { // Paper start - cache regionfile does not exist state -+ this.markNonExisting(regionPos); -+ return null; // CraftBukkit -+ } else { -+ this.createRegionFile(regionPos); -+ } -+ // Paper end - cache regionfile does not exist state -+ FileUtil.createDirectoriesSafe(this.folder); // Paper - only create directory if not existing only - moved from above - RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync); - - this.regionCache.putAndMoveToFirst(i, regionfile1); diff --git a/patches/server/0037-Further-improve-server-tick-loop.patch b/patches/server/0031-Further-improve-server-tick-loop.patch similarity index 100% rename from patches/server/0037-Further-improve-server-tick-loop.patch rename to patches/server/0031-Further-improve-server-tick-loop.patch diff --git a/patches/server/0038-Only-refresh-abilities-if-needed.patch b/patches/server/0032-Only-refresh-abilities-if-needed.patch similarity index 100% rename from patches/server/0038-Only-refresh-abilities-if-needed.patch rename to patches/server/0032-Only-refresh-abilities-if-needed.patch diff --git a/patches/server/0039-Entity-Origin-API.patch b/patches/server/0033-Entity-Origin-API.patch similarity index 100% rename from patches/server/0039-Entity-Origin-API.patch rename to patches/server/0033-Entity-Origin-API.patch diff --git a/patches/server/0040-Prevent-tile-entity-and-entity-crashes.patch b/patches/server/0034-Prevent-tile-entity-and-entity-crashes.patch similarity index 100% rename from patches/server/0040-Prevent-tile-entity-and-entity-crashes.patch rename to patches/server/0034-Prevent-tile-entity-and-entity-crashes.patch diff --git a/patches/server/0041-Configurable-top-of-nether-void-damage.patch b/patches/server/0035-Configurable-top-of-nether-void-damage.patch similarity index 100% rename from patches/server/0041-Configurable-top-of-nether-void-damage.patch rename to patches/server/0035-Configurable-top-of-nether-void-damage.patch diff --git a/patches/server/0042-Check-online-mode-before-converting-and-renaming-pla.patch b/patches/server/0036-Check-online-mode-before-converting-and-renaming-pla.patch similarity index 100% rename from patches/server/0042-Check-online-mode-before-converting-and-renaming-pla.patch rename to patches/server/0036-Check-online-mode-before-converting-and-renaming-pla.patch diff --git a/patches/server/0043-Always-tick-falling-blocks.patch b/patches/server/0037-Always-tick-falling-blocks.patch similarity index 100% rename from patches/server/0043-Always-tick-falling-blocks.patch rename to patches/server/0037-Always-tick-falling-blocks.patch diff --git a/patches/server/0044-Configurable-end-credits.patch b/patches/server/0038-Configurable-end-credits.patch similarity index 100% rename from patches/server/0044-Configurable-end-credits.patch rename to patches/server/0038-Configurable-end-credits.patch diff --git a/patches/server/0045-Fix-lag-from-explosions-processing-dead-entities.patch b/patches/server/0039-Fix-lag-from-explosions-processing-dead-entities.patch similarity index 100% rename from patches/server/0045-Fix-lag-from-explosions-processing-dead-entities.patch rename to patches/server/0039-Fix-lag-from-explosions-processing-dead-entities.patch diff --git a/patches/server/0046-Optimize-explosions.patch b/patches/server/0040-Optimize-explosions.patch similarity index 100% rename from patches/server/0046-Optimize-explosions.patch rename to patches/server/0040-Optimize-explosions.patch diff --git a/patches/server/0047-Disable-explosion-knockback.patch b/patches/server/0041-Disable-explosion-knockback.patch similarity index 100% rename from patches/server/0047-Disable-explosion-knockback.patch rename to patches/server/0041-Disable-explosion-knockback.patch diff --git a/patches/server/0048-Disable-thunder.patch b/patches/server/0042-Disable-thunder.patch similarity index 100% rename from patches/server/0048-Disable-thunder.patch rename to patches/server/0042-Disable-thunder.patch diff --git a/patches/server/0049-Disable-ice-and-snow.patch b/patches/server/0043-Disable-ice-and-snow.patch similarity index 100% rename from patches/server/0049-Disable-ice-and-snow.patch rename to patches/server/0043-Disable-ice-and-snow.patch diff --git a/patches/server/0050-Configurable-mob-spawner-tick-rate.patch b/patches/server/0044-Configurable-mob-spawner-tick-rate.patch similarity index 100% rename from patches/server/0050-Configurable-mob-spawner-tick-rate.patch rename to patches/server/0044-Configurable-mob-spawner-tick-rate.patch diff --git a/patches/server/0051-Implement-PlayerLocaleChangeEvent.patch b/patches/server/0045-Implement-PlayerLocaleChangeEvent.patch similarity index 100% rename from patches/server/0051-Implement-PlayerLocaleChangeEvent.patch rename to patches/server/0045-Implement-PlayerLocaleChangeEvent.patch diff --git a/patches/server/0052-Add-BeaconEffectEvent.patch b/patches/server/0046-Add-BeaconEffectEvent.patch similarity index 100% rename from patches/server/0052-Add-BeaconEffectEvent.patch rename to patches/server/0046-Add-BeaconEffectEvent.patch diff --git a/patches/server/0053-Configurable-container-update-tick-rate.patch b/patches/server/0047-Configurable-container-update-tick-rate.patch similarity index 100% rename from patches/server/0053-Configurable-container-update-tick-rate.patch rename to patches/server/0047-Configurable-container-update-tick-rate.patch diff --git a/patches/server/0054-Use-UserCache-for-player-heads.patch b/patches/server/0048-Use-UserCache-for-player-heads.patch similarity index 100% rename from patches/server/0054-Use-UserCache-for-player-heads.patch rename to patches/server/0048-Use-UserCache-for-player-heads.patch diff --git a/patches/server/0055-Disable-spigot-tick-limiters.patch b/patches/server/0049-Disable-spigot-tick-limiters.patch similarity index 100% rename from patches/server/0055-Disable-spigot-tick-limiters.patch rename to patches/server/0049-Disable-spigot-tick-limiters.patch diff --git a/patches/server/0056-Add-PlayerInitialSpawnEvent.patch b/patches/server/0050-Add-PlayerInitialSpawnEvent.patch similarity index 100% rename from patches/server/0056-Add-PlayerInitialSpawnEvent.patch rename to patches/server/0050-Add-PlayerInitialSpawnEvent.patch diff --git a/patches/server/0057-Configurable-Disabling-Cat-Chest-Detection.patch b/patches/server/0051-Configurable-Disabling-Cat-Chest-Detection.patch similarity index 100% rename from patches/server/0057-Configurable-Disabling-Cat-Chest-Detection.patch rename to patches/server/0051-Configurable-Disabling-Cat-Chest-Detection.patch diff --git a/patches/server/0058-Ensure-commands-are-not-ran-async.patch b/patches/server/0052-Ensure-commands-are-not-ran-async.patch similarity index 100% rename from patches/server/0058-Ensure-commands-are-not-ran-async.patch rename to patches/server/0052-Ensure-commands-are-not-ran-async.patch diff --git a/patches/server/0059-All-chunks-are-slime-spawn-chunks-toggle.patch b/patches/server/0053-All-chunks-are-slime-spawn-chunks-toggle.patch similarity index 100% rename from patches/server/0059-All-chunks-are-slime-spawn-chunks-toggle.patch rename to patches/server/0053-All-chunks-are-slime-spawn-chunks-toggle.patch diff --git a/patches/server/0060-Expose-server-CommandMap.patch b/patches/server/0054-Expose-server-CommandMap.patch similarity index 100% rename from patches/server/0060-Expose-server-CommandMap.patch rename to patches/server/0054-Expose-server-CommandMap.patch diff --git a/patches/server/0061-Be-a-bit-more-informative-in-maxHealth-exception.patch b/patches/server/0055-Be-a-bit-more-informative-in-maxHealth-exception.patch similarity index 100% rename from patches/server/0061-Be-a-bit-more-informative-in-maxHealth-exception.patch rename to patches/server/0055-Be-a-bit-more-informative-in-maxHealth-exception.patch diff --git a/patches/server/0062-Player-Tab-List-and-Title-APIs.patch b/patches/server/0056-Player-Tab-List-and-Title-APIs.patch similarity index 100% rename from patches/server/0062-Player-Tab-List-and-Title-APIs.patch rename to patches/server/0056-Player-Tab-List-and-Title-APIs.patch diff --git a/patches/server/0063-Add-configurable-portal-search-radius.patch b/patches/server/0057-Add-configurable-portal-search-radius.patch similarity index 100% rename from patches/server/0063-Add-configurable-portal-search-radius.patch rename to patches/server/0057-Add-configurable-portal-search-radius.patch diff --git a/patches/server/0064-Add-velocity-warnings.patch b/patches/server/0058-Add-velocity-warnings.patch similarity index 100% rename from patches/server/0064-Add-velocity-warnings.patch rename to patches/server/0058-Add-velocity-warnings.patch diff --git a/patches/server/0065-Configurable-inter-world-teleportation-safety.patch b/patches/server/0059-Configurable-inter-world-teleportation-safety.patch similarity index 100% rename from patches/server/0065-Configurable-inter-world-teleportation-safety.patch rename to patches/server/0059-Configurable-inter-world-teleportation-safety.patch diff --git a/patches/server/0066-Add-exception-reporting-event.patch b/patches/server/0060-Add-exception-reporting-event.patch similarity index 100% rename from patches/server/0066-Add-exception-reporting-event.patch rename to patches/server/0060-Add-exception-reporting-event.patch diff --git a/patches/server/0067-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch b/patches/server/0061-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch similarity index 100% rename from patches/server/0067-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch rename to patches/server/0061-Don-t-nest-if-we-don-t-need-to-when-cerealising-text.patch diff --git a/patches/server/0068-Disable-Scoreboards-for-non-players-by-default.patch b/patches/server/0062-Disable-Scoreboards-for-non-players-by-default.patch similarity index 100% rename from patches/server/0068-Disable-Scoreboards-for-non-players-by-default.patch rename to patches/server/0062-Disable-Scoreboards-for-non-players-by-default.patch diff --git a/patches/server/0069-Add-methods-for-working-with-arrows-stuck-in-living-.patch b/patches/server/0063-Add-methods-for-working-with-arrows-stuck-in-living-.patch similarity index 100% rename from patches/server/0069-Add-methods-for-working-with-arrows-stuck-in-living-.patch rename to patches/server/0063-Add-methods-for-working-with-arrows-stuck-in-living-.patch diff --git a/patches/server/0070-Complete-resource-pack-API.patch b/patches/server/0064-Complete-resource-pack-API.patch similarity index 100% rename from patches/server/0070-Complete-resource-pack-API.patch rename to patches/server/0064-Complete-resource-pack-API.patch diff --git a/patches/server/0071-Default-loading-permissions.yml-before-plugins.patch b/patches/server/0065-Default-loading-permissions.yml-before-plugins.patch similarity index 100% rename from patches/server/0071-Default-loading-permissions.yml-before-plugins.patch rename to patches/server/0065-Default-loading-permissions.yml-before-plugins.patch diff --git a/patches/server/0072-Allow-Reloading-of-Custom-Permissions.patch b/patches/server/0066-Allow-Reloading-of-Custom-Permissions.patch similarity index 100% rename from patches/server/0072-Allow-Reloading-of-Custom-Permissions.patch rename to patches/server/0066-Allow-Reloading-of-Custom-Permissions.patch diff --git a/patches/server/0073-Remove-Metadata-on-reload.patch b/patches/server/0067-Remove-Metadata-on-reload.patch similarity index 100% rename from patches/server/0073-Remove-Metadata-on-reload.patch rename to patches/server/0067-Remove-Metadata-on-reload.patch diff --git a/patches/server/0074-Handle-Item-Meta-Inconsistencies.patch b/patches/server/0068-Handle-Item-Meta-Inconsistencies.patch similarity index 100% rename from patches/server/0074-Handle-Item-Meta-Inconsistencies.patch rename to patches/server/0068-Handle-Item-Meta-Inconsistencies.patch diff --git a/patches/server/0075-Configurable-Non-Player-Arrow-Despawn-Rate.patch b/patches/server/0069-Configurable-Non-Player-Arrow-Despawn-Rate.patch similarity index 100% rename from patches/server/0075-Configurable-Non-Player-Arrow-Despawn-Rate.patch rename to patches/server/0069-Configurable-Non-Player-Arrow-Despawn-Rate.patch diff --git a/patches/server/0076-Add-World-Util-Methods.patch b/patches/server/0070-Add-World-Util-Methods.patch similarity index 100% rename from patches/server/0076-Add-World-Util-Methods.patch rename to patches/server/0070-Add-World-Util-Methods.patch diff --git a/patches/server/0077-Custom-replacement-for-eaten-items.patch b/patches/server/0071-Custom-replacement-for-eaten-items.patch similarity index 100% rename from patches/server/0077-Custom-replacement-for-eaten-items.patch rename to patches/server/0071-Custom-replacement-for-eaten-items.patch diff --git a/patches/server/0078-handle-NaN-health-absorb-values-and-repair-bad-data.patch b/patches/server/0072-handle-NaN-health-absorb-values-and-repair-bad-data.patch similarity index 100% rename from patches/server/0078-handle-NaN-health-absorb-values-and-repair-bad-data.patch rename to patches/server/0072-handle-NaN-health-absorb-values-and-repair-bad-data.patch diff --git a/patches/server/0079-Use-a-Shared-Random-for-Entities.patch b/patches/server/0073-Use-a-Shared-Random-for-Entities.patch similarity index 100% rename from patches/server/0079-Use-a-Shared-Random-for-Entities.patch rename to patches/server/0073-Use-a-Shared-Random-for-Entities.patch diff --git a/patches/server/0080-Configurable-spawn-chances-for-skeleton-horses.patch b/patches/server/0074-Configurable-spawn-chances-for-skeleton-horses.patch similarity index 100% rename from patches/server/0080-Configurable-spawn-chances-for-skeleton-horses.patch rename to patches/server/0074-Configurable-spawn-chances-for-skeleton-horses.patch diff --git a/patches/server/0081-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch b/patches/server/0075-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch similarity index 100% rename from patches/server/0081-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch rename to patches/server/0075-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch diff --git a/patches/server/0082-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch b/patches/server/0076-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch similarity index 100% rename from patches/server/0082-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch rename to patches/server/0076-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch diff --git a/patches/server/0083-Entity-AddTo-RemoveFrom-World-Events.patch b/patches/server/0077-Entity-AddTo-RemoveFrom-World-Events.patch similarity index 100% rename from patches/server/0083-Entity-AddTo-RemoveFrom-World-Events.patch rename to patches/server/0077-Entity-AddTo-RemoveFrom-World-Events.patch diff --git a/patches/server/0084-Configurable-Chunk-Inhabited-Time.patch b/patches/server/0078-Configurable-Chunk-Inhabited-Time.patch similarity index 100% rename from patches/server/0084-Configurable-Chunk-Inhabited-Time.patch rename to patches/server/0078-Configurable-Chunk-Inhabited-Time.patch diff --git a/patches/server/0085-EntityPathfindEvent.patch b/patches/server/0079-EntityPathfindEvent.patch similarity index 100% rename from patches/server/0085-EntityPathfindEvent.patch rename to patches/server/0079-EntityPathfindEvent.patch diff --git a/patches/server/0086-Sanitise-RegionFileCache-and-make-configurable.patch b/patches/server/0080-Sanitise-RegionFileCache-and-make-configurable.patch similarity index 100% rename from patches/server/0086-Sanitise-RegionFileCache-and-make-configurable.patch rename to patches/server/0080-Sanitise-RegionFileCache-and-make-configurable.patch diff --git a/patches/server/0087-Do-not-load-chunks-for-Pathfinding.patch b/patches/server/0081-Do-not-load-chunks-for-Pathfinding.patch similarity index 100% rename from patches/server/0087-Do-not-load-chunks-for-Pathfinding.patch rename to patches/server/0081-Do-not-load-chunks-for-Pathfinding.patch diff --git a/patches/server/0088-Add-PlayerUseUnknownEntityEvent.patch b/patches/server/0082-Add-PlayerUseUnknownEntityEvent.patch similarity index 100% rename from patches/server/0088-Add-PlayerUseUnknownEntityEvent.patch rename to patches/server/0082-Add-PlayerUseUnknownEntityEvent.patch diff --git a/patches/server/0089-Configurable-Grass-Spread-Tick-Rate.patch b/patches/server/0083-Configurable-Grass-Spread-Tick-Rate.patch similarity index 100% rename from patches/server/0089-Configurable-Grass-Spread-Tick-Rate.patch rename to patches/server/0083-Configurable-Grass-Spread-Tick-Rate.patch diff --git a/patches/server/0090-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch b/patches/server/0084-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch similarity index 100% rename from patches/server/0090-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch rename to patches/server/0084-Fix-Cancelling-BlockPlaceEvent-triggering-physics.patch diff --git a/patches/server/0091-Optimize-DataBits.patch b/patches/server/0085-Optimize-DataBits.patch similarity index 100% rename from patches/server/0091-Optimize-DataBits.patch rename to patches/server/0085-Optimize-DataBits.patch diff --git a/patches/server/0092-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch b/patches/server/0086-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch similarity index 100% rename from patches/server/0092-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch rename to patches/server/0086-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch diff --git a/patches/server/0093-Configurable-Player-Collision.patch b/patches/server/0087-Configurable-Player-Collision.patch similarity index 100% rename from patches/server/0093-Configurable-Player-Collision.patch rename to patches/server/0087-Configurable-Player-Collision.patch diff --git a/patches/server/0094-Add-handshake-event-to-allow-plugins-to-handle-clien.patch b/patches/server/0088-Add-handshake-event-to-allow-plugins-to-handle-clien.patch similarity index 100% rename from patches/server/0094-Add-handshake-event-to-allow-plugins-to-handle-clien.patch rename to patches/server/0088-Add-handshake-event-to-allow-plugins-to-handle-clien.patch diff --git a/patches/server/0095-Configurable-RCON-IP-address.patch b/patches/server/0089-Configurable-RCON-IP-address.patch similarity index 100% rename from patches/server/0095-Configurable-RCON-IP-address.patch rename to patches/server/0089-Configurable-RCON-IP-address.patch diff --git a/patches/server/0096-EntityRegainHealthEvent-isFastRegen-API.patch b/patches/server/0090-EntityRegainHealthEvent-isFastRegen-API.patch similarity index 100% rename from patches/server/0096-EntityRegainHealthEvent-isFastRegen-API.patch rename to patches/server/0090-EntityRegainHealthEvent-isFastRegen-API.patch diff --git a/patches/server/0097-Add-ability-to-configure-frosted_ice-properties.patch b/patches/server/0091-Add-ability-to-configure-frosted_ice-properties.patch similarity index 100% rename from patches/server/0097-Add-ability-to-configure-frosted_ice-properties.patch rename to patches/server/0091-Add-ability-to-configure-frosted_ice-properties.patch diff --git a/patches/server/0098-remove-null-possibility-for-getServer-singleton.patch b/patches/server/0092-remove-null-possibility-for-getServer-singleton.patch similarity index 100% rename from patches/server/0098-remove-null-possibility-for-getServer-singleton.patch rename to patches/server/0092-remove-null-possibility-for-getServer-singleton.patch diff --git a/patches/server/0099-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch b/patches/server/0093-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch similarity index 100% rename from patches/server/0099-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch rename to patches/server/0093-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch diff --git a/patches/server/0100-LootTable-API-Replenishable-Lootables-Feature.patch b/patches/server/0094-LootTable-API-Replenishable-Lootables-Feature.patch similarity index 100% rename from patches/server/0100-LootTable-API-Replenishable-Lootables-Feature.patch rename to patches/server/0094-LootTable-API-Replenishable-Lootables-Feature.patch diff --git a/patches/server/0101-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch b/patches/server/0095-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch similarity index 100% rename from patches/server/0101-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch rename to patches/server/0095-Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch diff --git a/patches/server/0102-System-property-for-disabling-watchdoge.patch b/patches/server/0096-System-property-for-disabling-watchdoge.patch similarity index 100% rename from patches/server/0102-System-property-for-disabling-watchdoge.patch rename to patches/server/0096-System-property-for-disabling-watchdoge.patch diff --git a/patches/server/0103-Async-GameProfileCache-saving.patch b/patches/server/0097-Async-GameProfileCache-saving.patch similarity index 100% rename from patches/server/0103-Async-GameProfileCache-saving.patch rename to patches/server/0097-Async-GameProfileCache-saving.patch diff --git a/patches/server/0104-Optional-TNT-doesn-t-move-in-water.patch b/patches/server/0098-Optional-TNT-doesn-t-move-in-water.patch similarity index 100% rename from patches/server/0104-Optional-TNT-doesn-t-move-in-water.patch rename to patches/server/0098-Optional-TNT-doesn-t-move-in-water.patch diff --git a/patches/server/0105-Faster-redstone-torch-rapid-clock-removal.patch b/patches/server/0099-Faster-redstone-torch-rapid-clock-removal.patch similarity index 100% rename from patches/server/0105-Faster-redstone-torch-rapid-clock-removal.patch rename to patches/server/0099-Faster-redstone-torch-rapid-clock-removal.patch diff --git a/patches/server/0106-Add-server-name-parameter.patch b/patches/server/0100-Add-server-name-parameter.patch similarity index 100% rename from patches/server/0106-Add-server-name-parameter.patch rename to patches/server/0100-Add-server-name-parameter.patch diff --git a/patches/server/0107-Only-send-global-sounds-to-same-world-if-limiting-ra.patch b/patches/server/0101-Only-send-global-sounds-to-same-world-if-limiting-ra.patch similarity index 100% rename from patches/server/0107-Only-send-global-sounds-to-same-world-if-limiting-ra.patch rename to patches/server/0101-Only-send-global-sounds-to-same-world-if-limiting-ra.patch diff --git a/patches/server/0108-Avoid-blocking-on-Network-Manager-creation.patch b/patches/server/0102-Avoid-blocking-on-Network-Manager-creation.patch similarity index 100% rename from patches/server/0108-Avoid-blocking-on-Network-Manager-creation.patch rename to patches/server/0102-Avoid-blocking-on-Network-Manager-creation.patch diff --git a/patches/server/0109-Don-t-lookup-game-profiles-that-have-no-UUID-and-no-.patch b/patches/server/0103-Don-t-lookup-game-profiles-that-have-no-UUID-and-no-.patch similarity index 100% rename from patches/server/0109-Don-t-lookup-game-profiles-that-have-no-UUID-and-no-.patch rename to patches/server/0103-Don-t-lookup-game-profiles-that-have-no-UUID-and-no-.patch diff --git a/patches/server/0110-Add-setting-for-proxy-online-mode-status.patch b/patches/server/0104-Add-setting-for-proxy-online-mode-status.patch similarity index 100% rename from patches/server/0110-Add-setting-for-proxy-online-mode-status.patch rename to patches/server/0104-Add-setting-for-proxy-online-mode-status.patch diff --git a/patches/server/0111-Optimise-BlockState-s-hashCode-equals.patch b/patches/server/0105-Optimise-BlockState-s-hashCode-equals.patch similarity index 100% rename from patches/server/0111-Optimise-BlockState-s-hashCode-equals.patch rename to patches/server/0105-Optimise-BlockState-s-hashCode-equals.patch diff --git a/patches/server/0112-Configurable-packet-in-spam-threshold.patch b/patches/server/0106-Configurable-packet-in-spam-threshold.patch similarity index 100% rename from patches/server/0112-Configurable-packet-in-spam-threshold.patch rename to patches/server/0106-Configurable-packet-in-spam-threshold.patch diff --git a/patches/server/0113-Configurable-flying-kick-messages.patch b/patches/server/0107-Configurable-flying-kick-messages.patch similarity index 100% rename from patches/server/0113-Configurable-flying-kick-messages.patch rename to patches/server/0107-Configurable-flying-kick-messages.patch diff --git a/patches/server/0114-Add-EntityZapEvent.patch b/patches/server/0108-Add-EntityZapEvent.patch similarity index 100% rename from patches/server/0114-Add-EntityZapEvent.patch rename to patches/server/0108-Add-EntityZapEvent.patch diff --git a/patches/server/0115-Filter-bad-tile-entity-nbt-data-from-falling-blocks.patch b/patches/server/0109-Filter-bad-tile-entity-nbt-data-from-falling-blocks.patch similarity index 100% rename from patches/server/0115-Filter-bad-tile-entity-nbt-data-from-falling-blocks.patch rename to patches/server/0109-Filter-bad-tile-entity-nbt-data-from-falling-blocks.patch diff --git a/patches/server/0116-Cache-user-authenticator-threads.patch b/patches/server/0110-Cache-user-authenticator-threads.patch similarity index 100% rename from patches/server/0116-Cache-user-authenticator-threads.patch rename to patches/server/0110-Cache-user-authenticator-threads.patch diff --git a/patches/server/0117-Allow-Reloading-of-Command-Aliases.patch b/patches/server/0111-Allow-Reloading-of-Command-Aliases.patch similarity index 100% rename from patches/server/0117-Allow-Reloading-of-Command-Aliases.patch rename to patches/server/0111-Allow-Reloading-of-Command-Aliases.patch diff --git a/patches/server/0118-Add-source-to-PlayerExpChangeEvent.patch b/patches/server/0112-Add-source-to-PlayerExpChangeEvent.patch similarity index 100% rename from patches/server/0118-Add-source-to-PlayerExpChangeEvent.patch rename to patches/server/0112-Add-source-to-PlayerExpChangeEvent.patch diff --git a/patches/server/0119-Add-ProjectileCollideEvent.patch b/patches/server/0113-Add-ProjectileCollideEvent.patch similarity index 100% rename from patches/server/0119-Add-ProjectileCollideEvent.patch rename to patches/server/0113-Add-ProjectileCollideEvent.patch diff --git a/patches/server/0120-Prevent-Pathfinding-out-of-World-Border.patch b/patches/server/0114-Prevent-Pathfinding-out-of-World-Border.patch similarity index 100% rename from patches/server/0120-Prevent-Pathfinding-out-of-World-Border.patch rename to patches/server/0114-Prevent-Pathfinding-out-of-World-Border.patch diff --git a/patches/server/0121-Optimize-World.isLoaded-BlockPosition-Z.patch b/patches/server/0115-Optimize-World.isLoaded-BlockPosition-Z.patch similarity index 100% rename from patches/server/0121-Optimize-World.isLoaded-BlockPosition-Z.patch rename to patches/server/0115-Optimize-World.isLoaded-BlockPosition-Z.patch diff --git a/patches/server/0122-Bound-Treasure-Maps-to-World-Border.patch b/patches/server/0116-Bound-Treasure-Maps-to-World-Border.patch similarity index 100% rename from patches/server/0122-Bound-Treasure-Maps-to-World-Border.patch rename to patches/server/0116-Bound-Treasure-Maps-to-World-Border.patch diff --git a/patches/server/0123-Configurable-Cartographer-Treasure-Maps.patch b/patches/server/0117-Configurable-Cartographer-Treasure-Maps.patch similarity index 100% rename from patches/server/0123-Configurable-Cartographer-Treasure-Maps.patch rename to patches/server/0117-Configurable-Cartographer-Treasure-Maps.patch diff --git a/patches/server/0124-Add-API-methods-to-control-if-armour-stands-can-move.patch b/patches/server/0118-Add-API-methods-to-control-if-armour-stands-can-move.patch similarity index 100% rename from patches/server/0124-Add-API-methods-to-control-if-armour-stands-can-move.patch rename to patches/server/0118-Add-API-methods-to-control-if-armour-stands-can-move.patch diff --git a/patches/server/0125-String-based-Action-Bar-API.patch b/patches/server/0119-String-based-Action-Bar-API.patch similarity index 100% rename from patches/server/0125-String-based-Action-Bar-API.patch rename to patches/server/0119-String-based-Action-Bar-API.patch diff --git a/patches/server/0126-Properly-fix-item-duplication-bug.patch b/patches/server/0120-Properly-fix-item-duplication-bug.patch similarity index 100% rename from patches/server/0126-Properly-fix-item-duplication-bug.patch rename to patches/server/0120-Properly-fix-item-duplication-bug.patch diff --git a/patches/server/0127-Firework-API-s.patch b/patches/server/0121-Firework-API-s.patch similarity index 100% rename from patches/server/0127-Firework-API-s.patch rename to patches/server/0121-Firework-API-s.patch diff --git a/patches/server/0128-PlayerTeleportEndGatewayEvent.patch b/patches/server/0122-PlayerTeleportEndGatewayEvent.patch similarity index 100% rename from patches/server/0128-PlayerTeleportEndGatewayEvent.patch rename to patches/server/0122-PlayerTeleportEndGatewayEvent.patch diff --git a/patches/server/0129-Provide-E-TE-Chunk-count-stat-methods.patch b/patches/server/0123-Provide-E-TE-Chunk-count-stat-methods.patch similarity index 100% rename from patches/server/0129-Provide-E-TE-Chunk-count-stat-methods.patch rename to patches/server/0123-Provide-E-TE-Chunk-count-stat-methods.patch diff --git a/patches/server/0130-Enforce-Sync-Player-Saves.patch b/patches/server/0124-Enforce-Sync-Player-Saves.patch similarity index 100% rename from patches/server/0130-Enforce-Sync-Player-Saves.patch rename to patches/server/0124-Enforce-Sync-Player-Saves.patch diff --git a/patches/server/0131-Don-t-allow-entities-to-ride-themselves-572.patch b/patches/server/0125-Don-t-allow-entities-to-ride-themselves-572.patch similarity index 100% rename from patches/server/0131-Don-t-allow-entities-to-ride-themselves-572.patch rename to patches/server/0125-Don-t-allow-entities-to-ride-themselves-572.patch diff --git a/patches/server/0132-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch b/patches/server/0126-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch similarity index 100% rename from patches/server/0132-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch rename to patches/server/0126-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch diff --git a/patches/server/0133-Cap-Entity-Collisions.patch b/patches/server/0127-Cap-Entity-Collisions.patch similarity index 100% rename from patches/server/0133-Cap-Entity-Collisions.patch rename to patches/server/0127-Cap-Entity-Collisions.patch diff --git a/patches/server/0134-Remove-CraftScheduler-Async-Task-Debugger.patch b/patches/server/0128-Remove-CraftScheduler-Async-Task-Debugger.patch similarity index 100% rename from patches/server/0134-Remove-CraftScheduler-Async-Task-Debugger.patch rename to patches/server/0128-Remove-CraftScheduler-Async-Task-Debugger.patch diff --git a/patches/server/0135-Do-not-let-armorstands-drown.patch b/patches/server/0129-Do-not-let-armorstands-drown.patch similarity index 100% rename from patches/server/0135-Do-not-let-armorstands-drown.patch rename to patches/server/0129-Do-not-let-armorstands-drown.patch diff --git a/patches/server/0136-Properly-handle-async-calls-to-restart-the-server.patch b/patches/server/0130-Properly-handle-async-calls-to-restart-the-server.patch similarity index 100% rename from patches/server/0136-Properly-handle-async-calls-to-restart-the-server.patch rename to patches/server/0130-Properly-handle-async-calls-to-restart-the-server.patch diff --git a/patches/server/0137-Add-option-to-make-parrots-stay-on-shoulders-despite.patch b/patches/server/0131-Add-option-to-make-parrots-stay-on-shoulders-despite.patch similarity index 100% rename from patches/server/0137-Add-option-to-make-parrots-stay-on-shoulders-despite.patch rename to patches/server/0131-Add-option-to-make-parrots-stay-on-shoulders-despite.patch diff --git a/patches/server/0138-Add-configuration-option-to-prevent-player-names-fro.patch b/patches/server/0132-Add-configuration-option-to-prevent-player-names-fro.patch similarity index 100% rename from patches/server/0138-Add-configuration-option-to-prevent-player-names-fro.patch rename to patches/server/0132-Add-configuration-option-to-prevent-player-names-fro.patch diff --git a/patches/server/0139-Use-TerminalConsoleAppender-for-console-improvements.patch b/patches/server/0133-Use-TerminalConsoleAppender-for-console-improvements.patch similarity index 100% rename from patches/server/0139-Use-TerminalConsoleAppender-for-console-improvements.patch rename to patches/server/0133-Use-TerminalConsoleAppender-for-console-improvements.patch diff --git a/patches/server/0140-provide-a-configurable-option-to-disable-creeper-lin.patch b/patches/server/0134-provide-a-configurable-option-to-disable-creeper-lin.patch similarity index 100% rename from patches/server/0140-provide-a-configurable-option-to-disable-creeper-lin.patch rename to patches/server/0134-provide-a-configurable-option-to-disable-creeper-lin.patch diff --git a/patches/server/0141-Item-canEntityPickup.patch b/patches/server/0135-Item-canEntityPickup.patch similarity index 100% rename from patches/server/0141-Item-canEntityPickup.patch rename to patches/server/0135-Item-canEntityPickup.patch diff --git a/patches/server/0142-PlayerPickupItemEvent-setFlyAtPlayer.patch b/patches/server/0136-PlayerPickupItemEvent-setFlyAtPlayer.patch similarity index 100% rename from patches/server/0142-PlayerPickupItemEvent-setFlyAtPlayer.patch rename to patches/server/0136-PlayerPickupItemEvent-setFlyAtPlayer.patch diff --git a/patches/server/0143-PlayerAttemptPickupItemEvent.patch b/patches/server/0137-PlayerAttemptPickupItemEvent.patch similarity index 100% rename from patches/server/0143-PlayerAttemptPickupItemEvent.patch rename to patches/server/0137-PlayerAttemptPickupItemEvent.patch diff --git a/patches/server/0144-Do-not-submit-profile-lookups-to-worldgen-threads.patch b/patches/server/0138-Do-not-submit-profile-lookups-to-worldgen-threads.patch similarity index 100% rename from patches/server/0144-Do-not-submit-profile-lookups-to-worldgen-threads.patch rename to patches/server/0138-Do-not-submit-profile-lookups-to-worldgen-threads.patch diff --git a/patches/server/0145-Add-UnknownCommandEvent.patch b/patches/server/0139-Add-UnknownCommandEvent.patch similarity index 100% rename from patches/server/0145-Add-UnknownCommandEvent.patch rename to patches/server/0139-Add-UnknownCommandEvent.patch diff --git a/patches/server/0146-Basic-PlayerProfile-API.patch b/patches/server/0140-Basic-PlayerProfile-API.patch similarity index 100% rename from patches/server/0146-Basic-PlayerProfile-API.patch rename to patches/server/0140-Basic-PlayerProfile-API.patch diff --git a/patches/server/0147-Shoulder-Entities-Release-API.patch b/patches/server/0141-Shoulder-Entities-Release-API.patch similarity index 100% rename from patches/server/0147-Shoulder-Entities-Release-API.patch rename to patches/server/0141-Shoulder-Entities-Release-API.patch diff --git a/patches/server/0148-Profile-Lookup-Events.patch b/patches/server/0142-Profile-Lookup-Events.patch similarity index 100% rename from patches/server/0148-Profile-Lookup-Events.patch rename to patches/server/0142-Profile-Lookup-Events.patch diff --git a/patches/server/0149-Block-player-logins-during-server-shutdown.patch b/patches/server/0143-Block-player-logins-during-server-shutdown.patch similarity index 100% rename from patches/server/0149-Block-player-logins-during-server-shutdown.patch rename to patches/server/0143-Block-player-logins-during-server-shutdown.patch diff --git a/patches/server/0150-Entity-fromMobSpawner.patch b/patches/server/0144-Entity-fromMobSpawner.patch similarity index 100% rename from patches/server/0150-Entity-fromMobSpawner.patch rename to patches/server/0144-Entity-fromMobSpawner.patch diff --git a/patches/server/0151-Improve-the-Saddle-API-for-Horses.patch b/patches/server/0145-Improve-the-Saddle-API-for-Horses.patch similarity index 100% rename from patches/server/0151-Improve-the-Saddle-API-for-Horses.patch rename to patches/server/0145-Improve-the-Saddle-API-for-Horses.patch diff --git a/patches/server/0152-Implement-ensureServerConversions-API.patch b/patches/server/0146-Implement-ensureServerConversions-API.patch similarity index 100% rename from patches/server/0152-Implement-ensureServerConversions-API.patch rename to patches/server/0146-Implement-ensureServerConversions-API.patch diff --git a/patches/server/0153-Implement-getI18NDisplayName.patch b/patches/server/0147-Implement-getI18NDisplayName.patch similarity index 100% rename from patches/server/0153-Implement-getI18NDisplayName.patch rename to patches/server/0147-Implement-getI18NDisplayName.patch diff --git a/patches/server/0154-ProfileWhitelistVerifyEvent.patch b/patches/server/0148-ProfileWhitelistVerifyEvent.patch similarity index 100% rename from patches/server/0154-ProfileWhitelistVerifyEvent.patch rename to patches/server/0148-ProfileWhitelistVerifyEvent.patch diff --git a/patches/server/0155-Fix-this-stupid-bullshit.patch b/patches/server/0149-Fix-this-stupid-bullshit.patch similarity index 100% rename from patches/server/0155-Fix-this-stupid-bullshit.patch rename to patches/server/0149-Fix-this-stupid-bullshit.patch diff --git a/patches/server/0156-LivingEntity-setKiller.patch b/patches/server/0150-LivingEntity-setKiller.patch similarity index 100% rename from patches/server/0156-LivingEntity-setKiller.patch rename to patches/server/0150-LivingEntity-setKiller.patch diff --git a/patches/server/0157-Ocelot-despawns-should-honor-nametags-and-leash.patch b/patches/server/0151-Ocelot-despawns-should-honor-nametags-and-leash.patch similarity index 100% rename from patches/server/0157-Ocelot-despawns-should-honor-nametags-and-leash.patch rename to patches/server/0151-Ocelot-despawns-should-honor-nametags-and-leash.patch diff --git a/patches/server/0158-Reset-spawner-timer-when-spawner-event-is-cancelled.patch b/patches/server/0152-Reset-spawner-timer-when-spawner-event-is-cancelled.patch similarity index 100% rename from patches/server/0158-Reset-spawner-timer-when-spawner-event-is-cancelled.patch rename to patches/server/0152-Reset-spawner-timer-when-spawner-event-is-cancelled.patch diff --git a/patches/server/0159-Allow-specifying-a-custom-authentication-servers-dow.patch b/patches/server/0153-Allow-specifying-a-custom-authentication-servers-dow.patch similarity index 100% rename from patches/server/0159-Allow-specifying-a-custom-authentication-servers-dow.patch rename to patches/server/0153-Allow-specifying-a-custom-authentication-servers-dow.patch diff --git a/patches/server/0160-Handle-plugin-prefixes-using-Log4J-configuration.patch b/patches/server/0154-Handle-plugin-prefixes-using-Log4J-configuration.patch similarity index 100% rename from patches/server/0160-Handle-plugin-prefixes-using-Log4J-configuration.patch rename to patches/server/0154-Handle-plugin-prefixes-using-Log4J-configuration.patch diff --git a/patches/server/0161-Improve-Log4J-Configuration-Plugin-Loggers.patch b/patches/server/0155-Improve-Log4J-Configuration-Plugin-Loggers.patch similarity index 100% rename from patches/server/0161-Improve-Log4J-Configuration-Plugin-Loggers.patch rename to patches/server/0155-Improve-Log4J-Configuration-Plugin-Loggers.patch diff --git a/patches/server/0162-Add-PlayerJumpEvent.patch b/patches/server/0156-Add-PlayerJumpEvent.patch similarity index 100% rename from patches/server/0162-Add-PlayerJumpEvent.patch rename to patches/server/0156-Add-PlayerJumpEvent.patch diff --git a/patches/server/0163-handle-ServerboundKeepAlivePacket-async.patch b/patches/server/0157-handle-ServerboundKeepAlivePacket-async.patch similarity index 100% rename from patches/server/0163-handle-ServerboundKeepAlivePacket-async.patch rename to patches/server/0157-handle-ServerboundKeepAlivePacket-async.patch diff --git a/patches/server/0164-Expose-client-protocol-version-and-virtual-host.patch b/patches/server/0158-Expose-client-protocol-version-and-virtual-host.patch similarity index 100% rename from patches/server/0164-Expose-client-protocol-version-and-virtual-host.patch rename to patches/server/0158-Expose-client-protocol-version-and-virtual-host.patch diff --git a/patches/server/0165-revert-serverside-behavior-of-keepalives.patch b/patches/server/0159-revert-serverside-behavior-of-keepalives.patch similarity index 100% rename from patches/server/0165-revert-serverside-behavior-of-keepalives.patch rename to patches/server/0159-revert-serverside-behavior-of-keepalives.patch diff --git a/patches/server/0166-Send-attack-SoundEffects-only-to-players-who-can-see.patch b/patches/server/0160-Send-attack-SoundEffects-only-to-players-who-can-see.patch similarity index 100% rename from patches/server/0166-Send-attack-SoundEffects-only-to-players-who-can-see.patch rename to patches/server/0160-Send-attack-SoundEffects-only-to-players-who-can-see.patch diff --git a/patches/server/0167-Add-PlayerArmorChangeEvent.patch b/patches/server/0161-Add-PlayerArmorChangeEvent.patch similarity index 100% rename from patches/server/0167-Add-PlayerArmorChangeEvent.patch rename to patches/server/0161-Add-PlayerArmorChangeEvent.patch diff --git a/patches/server/0168-Prevent-logins-from-being-processed-when-the-player-.patch b/patches/server/0162-Prevent-logins-from-being-processed-when-the-player-.patch similarity index 100% rename from patches/server/0168-Prevent-logins-from-being-processed-when-the-player-.patch rename to patches/server/0162-Prevent-logins-from-being-processed-when-the-player-.patch diff --git a/patches/server/0169-Fix-MC-117075-TE-Unload-Lag-Spike.patch b/patches/server/0163-Fix-MC-117075-TE-Unload-Lag-Spike.patch similarity index 100% rename from patches/server/0169-Fix-MC-117075-TE-Unload-Lag-Spike.patch rename to patches/server/0163-Fix-MC-117075-TE-Unload-Lag-Spike.patch diff --git a/patches/server/0170-use-CB-BlockState-implementations-for-captured-block.patch b/patches/server/0164-use-CB-BlockState-implementations-for-captured-block.patch similarity index 100% rename from patches/server/0170-use-CB-BlockState-implementations-for-captured-block.patch rename to patches/server/0164-use-CB-BlockState-implementations-for-captured-block.patch diff --git a/patches/server/0171-API-to-get-a-BlockState-without-a-snapshot.patch b/patches/server/0165-API-to-get-a-BlockState-without-a-snapshot.patch similarity index 100% rename from patches/server/0171-API-to-get-a-BlockState-without-a-snapshot.patch rename to patches/server/0165-API-to-get-a-BlockState-without-a-snapshot.patch diff --git a/patches/server/0172-AsyncTabCompleteEvent.patch b/patches/server/0166-AsyncTabCompleteEvent.patch similarity index 100% rename from patches/server/0172-AsyncTabCompleteEvent.patch rename to patches/server/0166-AsyncTabCompleteEvent.patch diff --git a/patches/server/0173-PlayerPickupExperienceEvent.patch b/patches/server/0167-PlayerPickupExperienceEvent.patch similarity index 100% rename from patches/server/0173-PlayerPickupExperienceEvent.patch rename to patches/server/0167-PlayerPickupExperienceEvent.patch diff --git a/patches/server/0174-Ability-to-apply-mending-to-XP-API.patch b/patches/server/0168-Ability-to-apply-mending-to-XP-API.patch similarity index 100% rename from patches/server/0174-Ability-to-apply-mending-to-XP-API.patch rename to patches/server/0168-Ability-to-apply-mending-to-XP-API.patch diff --git a/patches/server/0175-PlayerNaturallySpawnCreaturesEvent.patch b/patches/server/0169-PlayerNaturallySpawnCreaturesEvent.patch similarity index 100% rename from patches/server/0175-PlayerNaturallySpawnCreaturesEvent.patch rename to patches/server/0169-PlayerNaturallySpawnCreaturesEvent.patch diff --git a/patches/server/0176-Add-setPlayerProfile-API-for-Skulls.patch b/patches/server/0170-Add-setPlayerProfile-API-for-Skulls.patch similarity index 100% rename from patches/server/0176-Add-setPlayerProfile-API-for-Skulls.patch rename to patches/server/0170-Add-setPlayerProfile-API-for-Skulls.patch diff --git a/patches/server/0177-PreCreatureSpawnEvent.patch b/patches/server/0171-PreCreatureSpawnEvent.patch similarity index 100% rename from patches/server/0177-PreCreatureSpawnEvent.patch rename to patches/server/0171-PreCreatureSpawnEvent.patch diff --git a/patches/server/0178-Fill-Profile-Property-Events.patch b/patches/server/0172-Fill-Profile-Property-Events.patch similarity index 100% rename from patches/server/0178-Fill-Profile-Property-Events.patch rename to patches/server/0172-Fill-Profile-Property-Events.patch diff --git a/patches/server/0179-PlayerAdvancementCriterionGrantEvent.patch b/patches/server/0173-PlayerAdvancementCriterionGrantEvent.patch similarity index 100% rename from patches/server/0179-PlayerAdvancementCriterionGrantEvent.patch rename to patches/server/0173-PlayerAdvancementCriterionGrantEvent.patch diff --git a/patches/server/0180-Add-ArmorStand-Item-Meta.patch b/patches/server/0174-Add-ArmorStand-Item-Meta.patch similarity index 100% rename from patches/server/0180-Add-ArmorStand-Item-Meta.patch rename to patches/server/0174-Add-ArmorStand-Item-Meta.patch diff --git a/patches/server/0181-Extend-Player-Interact-cancellation.patch b/patches/server/0175-Extend-Player-Interact-cancellation.patch similarity index 100% rename from patches/server/0181-Extend-Player-Interact-cancellation.patch rename to patches/server/0175-Extend-Player-Interact-cancellation.patch diff --git a/patches/server/0182-Tameable-getOwnerUniqueId-API.patch b/patches/server/0176-Tameable-getOwnerUniqueId-API.patch similarity index 100% rename from patches/server/0182-Tameable-getOwnerUniqueId-API.patch rename to patches/server/0176-Tameable-getOwnerUniqueId-API.patch diff --git a/patches/server/0183-Toggleable-player-crits-helps-mitigate-hacked-client.patch b/patches/server/0177-Toggleable-player-crits-helps-mitigate-hacked-client.patch similarity index 100% rename from patches/server/0183-Toggleable-player-crits-helps-mitigate-hacked-client.patch rename to patches/server/0177-Toggleable-player-crits-helps-mitigate-hacked-client.patch diff --git a/patches/server/0184-Disable-Explicit-Network-Manager-Flushing.patch b/patches/server/0178-Disable-Explicit-Network-Manager-Flushing.patch similarity index 100% rename from patches/server/0184-Disable-Explicit-Network-Manager-Flushing.patch rename to patches/server/0178-Disable-Explicit-Network-Manager-Flushing.patch diff --git a/patches/server/0185-Implement-extended-PaperServerListPingEvent.patch b/patches/server/0179-Implement-extended-PaperServerListPingEvent.patch similarity index 100% rename from patches/server/0185-Implement-extended-PaperServerListPingEvent.patch rename to patches/server/0179-Implement-extended-PaperServerListPingEvent.patch diff --git a/patches/server/0186-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch b/patches/server/0180-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch similarity index 100% rename from patches/server/0186-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch rename to patches/server/0180-Ability-to-change-PlayerProfile-in-AsyncPreLoginEven.patch diff --git a/patches/server/0187-Player.setPlayerProfile-API.patch b/patches/server/0181-Player.setPlayerProfile-API.patch similarity index 100% rename from patches/server/0187-Player.setPlayerProfile-API.patch rename to patches/server/0181-Player.setPlayerProfile-API.patch diff --git a/patches/server/0188-getPlayerUniqueId-API.patch b/patches/server/0182-getPlayerUniqueId-API.patch similarity index 100% rename from patches/server/0188-getPlayerUniqueId-API.patch rename to patches/server/0182-getPlayerUniqueId-API.patch diff --git a/patches/server/0189-Improved-Async-Task-Scheduler.patch b/patches/server/0183-Improved-Async-Task-Scheduler.patch similarity index 100% rename from patches/server/0189-Improved-Async-Task-Scheduler.patch rename to patches/server/0183-Improved-Async-Task-Scheduler.patch diff --git a/patches/server/0190-Make-legacy-ping-handler-more-reliable.patch b/patches/server/0184-Make-legacy-ping-handler-more-reliable.patch similarity index 100% rename from patches/server/0190-Make-legacy-ping-handler-more-reliable.patch rename to patches/server/0184-Make-legacy-ping-handler-more-reliable.patch diff --git a/patches/server/0191-Call-PaperServerListPingEvent-for-legacy-pings.patch b/patches/server/0185-Call-PaperServerListPingEvent-for-legacy-pings.patch similarity index 100% rename from patches/server/0191-Call-PaperServerListPingEvent-for-legacy-pings.patch rename to patches/server/0185-Call-PaperServerListPingEvent-for-legacy-pings.patch diff --git a/patches/server/0192-Flag-to-disable-the-channel-limit.patch b/patches/server/0186-Flag-to-disable-the-channel-limit.patch similarity index 100% rename from patches/server/0192-Flag-to-disable-the-channel-limit.patch rename to patches/server/0186-Flag-to-disable-the-channel-limit.patch diff --git a/patches/server/0193-Add-openSign-method-to-HumanEntity.patch b/patches/server/0187-Add-openSign-method-to-HumanEntity.patch similarity index 100% rename from patches/server/0193-Add-openSign-method-to-HumanEntity.patch rename to patches/server/0187-Add-openSign-method-to-HumanEntity.patch diff --git a/patches/server/0194-Configurable-sprint-interruption-on-attack.patch b/patches/server/0188-Configurable-sprint-interruption-on-attack.patch similarity index 100% rename from patches/server/0194-Configurable-sprint-interruption-on-attack.patch rename to patches/server/0188-Configurable-sprint-interruption-on-attack.patch diff --git a/patches/server/0195-EndermanEscapeEvent.patch b/patches/server/0189-EndermanEscapeEvent.patch similarity index 100% rename from patches/server/0195-EndermanEscapeEvent.patch rename to patches/server/0189-EndermanEscapeEvent.patch diff --git a/patches/server/0196-Enderman.teleportRandomly.patch b/patches/server/0190-Enderman.teleportRandomly.patch similarity index 100% rename from patches/server/0196-Enderman.teleportRandomly.patch rename to patches/server/0190-Enderman.teleportRandomly.patch diff --git a/patches/server/0197-Block-Enderpearl-Travel-Exploit.patch b/patches/server/0191-Block-Enderpearl-Travel-Exploit.patch similarity index 100% rename from patches/server/0197-Block-Enderpearl-Travel-Exploit.patch rename to patches/server/0191-Block-Enderpearl-Travel-Exploit.patch diff --git a/patches/server/0198-Expand-World.spawnParticle-API-and-add-Builder.patch b/patches/server/0192-Expand-World.spawnParticle-API-and-add-Builder.patch similarity index 100% rename from patches/server/0198-Expand-World.spawnParticle-API-and-add-Builder.patch rename to patches/server/0192-Expand-World.spawnParticle-API-and-add-Builder.patch diff --git a/patches/server/0199-Prevent-Frosted-Ice-from-loading-holding-chunks.patch b/patches/server/0193-Prevent-Frosted-Ice-from-loading-holding-chunks.patch similarity index 100% rename from patches/server/0199-Prevent-Frosted-Ice-from-loading-holding-chunks.patch rename to patches/server/0193-Prevent-Frosted-Ice-from-loading-holding-chunks.patch diff --git a/patches/server/0200-EndermanAttackPlayerEvent.patch b/patches/server/0194-EndermanAttackPlayerEvent.patch similarity index 100% rename from patches/server/0200-EndermanAttackPlayerEvent.patch rename to patches/server/0194-EndermanAttackPlayerEvent.patch diff --git a/patches/server/0201-WitchConsumePotionEvent.patch b/patches/server/0195-WitchConsumePotionEvent.patch similarity index 100% rename from patches/server/0201-WitchConsumePotionEvent.patch rename to patches/server/0195-WitchConsumePotionEvent.patch diff --git a/patches/server/0202-WitchThrowPotionEvent.patch b/patches/server/0196-WitchThrowPotionEvent.patch similarity index 100% rename from patches/server/0202-WitchThrowPotionEvent.patch rename to patches/server/0196-WitchThrowPotionEvent.patch diff --git a/patches/server/0203-Allow-spawning-Item-entities-with-World.spawnEntity.patch b/patches/server/0197-Allow-spawning-Item-entities-with-World.spawnEntity.patch similarity index 100% rename from patches/server/0203-Allow-spawning-Item-entities-with-World.spawnEntity.patch rename to patches/server/0197-Allow-spawning-Item-entities-with-World.spawnEntity.patch diff --git a/patches/server/0204-WitchReadyPotionEvent.patch b/patches/server/0198-WitchReadyPotionEvent.patch similarity index 100% rename from patches/server/0204-WitchReadyPotionEvent.patch rename to patches/server/0198-WitchReadyPotionEvent.patch diff --git a/patches/server/0205-ItemStack-getMaxItemUseDuration.patch b/patches/server/0199-ItemStack-getMaxItemUseDuration.patch similarity index 100% rename from patches/server/0205-ItemStack-getMaxItemUseDuration.patch rename to patches/server/0199-ItemStack-getMaxItemUseDuration.patch diff --git a/patches/server/0206-Implement-EntityTeleportEndGatewayEvent.patch b/patches/server/0200-Implement-EntityTeleportEndGatewayEvent.patch similarity index 100% rename from patches/server/0206-Implement-EntityTeleportEndGatewayEvent.patch rename to patches/server/0200-Implement-EntityTeleportEndGatewayEvent.patch diff --git a/patches/server/0207-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch b/patches/server/0201-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch similarity index 100% rename from patches/server/0207-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch rename to patches/server/0201-Unset-Ignited-flag-on-cancel-of-Explosion-Event.patch diff --git a/patches/server/0208-Fix-CraftEntity-hashCode.patch b/patches/server/0202-Fix-CraftEntity-hashCode.patch similarity index 100% rename from patches/server/0208-Fix-CraftEntity-hashCode.patch rename to patches/server/0202-Fix-CraftEntity-hashCode.patch diff --git a/patches/server/0209-Configurable-Alternative-LootPool-Luck-Formula.patch b/patches/server/0203-Configurable-Alternative-LootPool-Luck-Formula.patch similarity index 100% rename from patches/server/0209-Configurable-Alternative-LootPool-Luck-Formula.patch rename to patches/server/0203-Configurable-Alternative-LootPool-Luck-Formula.patch diff --git a/patches/server/0210-Print-Error-details-when-failing-to-save-player-data.patch b/patches/server/0204-Print-Error-details-when-failing-to-save-player-data.patch similarity index 100% rename from patches/server/0210-Print-Error-details-when-failing-to-save-player-data.patch rename to patches/server/0204-Print-Error-details-when-failing-to-save-player-data.patch diff --git a/patches/server/0211-Make-shield-blocking-delay-configurable.patch b/patches/server/0205-Make-shield-blocking-delay-configurable.patch similarity index 100% rename from patches/server/0211-Make-shield-blocking-delay-configurable.patch rename to patches/server/0205-Make-shield-blocking-delay-configurable.patch diff --git a/patches/server/0212-Improve-EntityShootBowEvent.patch b/patches/server/0206-Improve-EntityShootBowEvent.patch similarity index 100% rename from patches/server/0212-Improve-EntityShootBowEvent.patch rename to patches/server/0206-Improve-EntityShootBowEvent.patch diff --git a/patches/server/0213-PlayerReadyArrowEvent.patch b/patches/server/0207-PlayerReadyArrowEvent.patch similarity index 100% rename from patches/server/0213-PlayerReadyArrowEvent.patch rename to patches/server/0207-PlayerReadyArrowEvent.patch diff --git a/patches/server/0214-Implement-EntityKnockbackByEntityEvent-and-EntityPus.patch b/patches/server/0208-Implement-EntityKnockbackByEntityEvent-and-EntityPus.patch similarity index 100% rename from patches/server/0214-Implement-EntityKnockbackByEntityEvent-and-EntityPus.patch rename to patches/server/0208-Implement-EntityKnockbackByEntityEvent-and-EntityPus.patch diff --git a/patches/server/0215-Expand-Explosions-API.patch b/patches/server/0209-Expand-Explosions-API.patch similarity index 100% rename from patches/server/0215-Expand-Explosions-API.patch rename to patches/server/0209-Expand-Explosions-API.patch diff --git a/patches/server/0216-LivingEntity-Hand-Raised-Item-Use-API.patch b/patches/server/0210-LivingEntity-Hand-Raised-Item-Use-API.patch similarity index 100% rename from patches/server/0216-LivingEntity-Hand-Raised-Item-Use-API.patch rename to patches/server/0210-LivingEntity-Hand-Raised-Item-Use-API.patch diff --git a/patches/server/0217-RangedEntity-API.patch b/patches/server/0211-RangedEntity-API.patch similarity index 100% rename from patches/server/0217-RangedEntity-API.patch rename to patches/server/0211-RangedEntity-API.patch diff --git a/patches/server/0218-Add-config-to-disable-ender-dragon-legacy-check.patch b/patches/server/0212-Add-config-to-disable-ender-dragon-legacy-check.patch similarity index 100% rename from patches/server/0218-Add-config-to-disable-ender-dragon-legacy-check.patch rename to patches/server/0212-Add-config-to-disable-ender-dragon-legacy-check.patch diff --git a/patches/server/0219-Implement-World.getEntity-UUID-API.patch b/patches/server/0213-Implement-World.getEntity-UUID-API.patch similarity index 100% rename from patches/server/0219-Implement-World.getEntity-UUID-API.patch rename to patches/server/0213-Implement-World.getEntity-UUID-API.patch diff --git a/patches/server/0220-InventoryCloseEvent-Reason-API.patch b/patches/server/0214-InventoryCloseEvent-Reason-API.patch similarity index 100% rename from patches/server/0220-InventoryCloseEvent-Reason-API.patch rename to patches/server/0214-InventoryCloseEvent-Reason-API.patch diff --git a/patches/server/0221-Vex-get-setSummoner-API.patch b/patches/server/0215-Vex-get-setSummoner-API.patch similarity index 100% rename from patches/server/0221-Vex-get-setSummoner-API.patch rename to patches/server/0215-Vex-get-setSummoner-API.patch diff --git a/patches/server/0222-Refresh-player-inventory-when-cancelling-PlayerInter.patch b/patches/server/0216-Refresh-player-inventory-when-cancelling-PlayerInter.patch similarity index 100% rename from patches/server/0222-Refresh-player-inventory-when-cancelling-PlayerInter.patch rename to patches/server/0216-Refresh-player-inventory-when-cancelling-PlayerInter.patch diff --git a/patches/server/0223-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch b/patches/server/0217-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch similarity index 100% rename from patches/server/0223-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch rename to patches/server/0217-Use-AsyncAppender-to-keep-logging-IO-off-main-thread.patch diff --git a/patches/server/0224-add-more-information-to-Entity.toString.patch b/patches/server/0218-add-more-information-to-Entity.toString.patch similarity index 100% rename from patches/server/0224-add-more-information-to-Entity.toString.patch rename to patches/server/0218-add-more-information-to-Entity.toString.patch diff --git a/patches/server/0225-EnderDragon-Events.patch b/patches/server/0219-EnderDragon-Events.patch similarity index 100% rename from patches/server/0225-EnderDragon-Events.patch rename to patches/server/0219-EnderDragon-Events.patch diff --git a/patches/server/0226-PlayerElytraBoostEvent.patch b/patches/server/0220-PlayerElytraBoostEvent.patch similarity index 100% rename from patches/server/0226-PlayerElytraBoostEvent.patch rename to patches/server/0220-PlayerElytraBoostEvent.patch diff --git a/patches/server/0227-PlayerLaunchProjectileEvent.patch b/patches/server/0221-PlayerLaunchProjectileEvent.patch similarity index 100% rename from patches/server/0227-PlayerLaunchProjectileEvent.patch rename to patches/server/0221-PlayerLaunchProjectileEvent.patch diff --git a/patches/server/0228-Improve-BlockPosition-inlining.patch b/patches/server/0222-Improve-BlockPosition-inlining.patch similarity index 100% rename from patches/server/0228-Improve-BlockPosition-inlining.patch rename to patches/server/0222-Improve-BlockPosition-inlining.patch diff --git a/patches/server/0229-Option-to-prevent-armor-stands-from-doing-entity-loo.patch b/patches/server/0223-Option-to-prevent-armor-stands-from-doing-entity-loo.patch similarity index 100% rename from patches/server/0229-Option-to-prevent-armor-stands-from-doing-entity-loo.patch rename to patches/server/0223-Option-to-prevent-armor-stands-from-doing-entity-loo.patch diff --git a/patches/server/0230-Vanished-players-don-t-have-rights.patch b/patches/server/0224-Vanished-players-don-t-have-rights.patch similarity index 100% rename from patches/server/0230-Vanished-players-don-t-have-rights.patch rename to patches/server/0224-Vanished-players-don-t-have-rights.patch diff --git a/patches/server/0231-Allow-disabling-armour-stand-ticking.patch b/patches/server/0225-Allow-disabling-armour-stand-ticking.patch similarity index 100% rename from patches/server/0231-Allow-disabling-armour-stand-ticking.patch rename to patches/server/0225-Allow-disabling-armour-stand-ticking.patch diff --git a/patches/server/0232-SkeletonHorse-Additions.patch b/patches/server/0226-SkeletonHorse-Additions.patch similarity index 100% rename from patches/server/0232-SkeletonHorse-Additions.patch rename to patches/server/0226-SkeletonHorse-Additions.patch diff --git a/patches/server/0233-Don-t-call-getItemMeta-on-hasItemMeta.patch b/patches/server/0227-Don-t-call-getItemMeta-on-hasItemMeta.patch similarity index 100% rename from patches/server/0233-Don-t-call-getItemMeta-on-hasItemMeta.patch rename to patches/server/0227-Don-t-call-getItemMeta-on-hasItemMeta.patch diff --git a/patches/server/0234-Implement-Expanded-ArmorStand-API.patch b/patches/server/0228-Implement-Expanded-ArmorStand-API.patch similarity index 100% rename from patches/server/0234-Implement-Expanded-ArmorStand-API.patch rename to patches/server/0228-Implement-Expanded-ArmorStand-API.patch diff --git a/patches/server/0235-AnvilDamageEvent.patch b/patches/server/0229-AnvilDamageEvent.patch similarity index 100% rename from patches/server/0235-AnvilDamageEvent.patch rename to patches/server/0229-AnvilDamageEvent.patch diff --git a/patches/server/0236-Add-TNTPrimeEvent.patch b/patches/server/0230-Add-TNTPrimeEvent.patch similarity index 100% rename from patches/server/0236-Add-TNTPrimeEvent.patch rename to patches/server/0230-Add-TNTPrimeEvent.patch diff --git a/patches/server/0237-Break-up-and-make-tab-spam-limits-configurable.patch b/patches/server/0231-Break-up-and-make-tab-spam-limits-configurable.patch similarity index 100% rename from patches/server/0237-Break-up-and-make-tab-spam-limits-configurable.patch rename to patches/server/0231-Break-up-and-make-tab-spam-limits-configurable.patch diff --git a/patches/server/0238-Fix-NBT-type-issues.patch b/patches/server/0232-Fix-NBT-type-issues.patch similarity index 100% rename from patches/server/0238-Fix-NBT-type-issues.patch rename to patches/server/0232-Fix-NBT-type-issues.patch diff --git a/patches/server/0239-Remove-unnecessary-itemmeta-handling.patch b/patches/server/0233-Remove-unnecessary-itemmeta-handling.patch similarity index 100% rename from patches/server/0239-Remove-unnecessary-itemmeta-handling.patch rename to patches/server/0233-Remove-unnecessary-itemmeta-handling.patch diff --git a/patches/server/0240-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch b/patches/server/0234-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch similarity index 100% rename from patches/server/0240-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch rename to patches/server/0234-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch diff --git a/patches/server/0241-Add-Early-Warning-Feature-to-WatchDog.patch b/patches/server/0235-Add-Early-Warning-Feature-to-WatchDog.patch similarity index 100% rename from patches/server/0241-Add-Early-Warning-Feature-to-WatchDog.patch rename to patches/server/0235-Add-Early-Warning-Feature-to-WatchDog.patch diff --git a/patches/server/0242-Use-ConcurrentHashMap-in-JsonList.patch b/patches/server/0236-Use-ConcurrentHashMap-in-JsonList.patch similarity index 100% rename from patches/server/0242-Use-ConcurrentHashMap-in-JsonList.patch rename to patches/server/0236-Use-ConcurrentHashMap-in-JsonList.patch diff --git a/patches/server/0243-Use-a-Queue-for-Queueing-Commands.patch b/patches/server/0237-Use-a-Queue-for-Queueing-Commands.patch similarity index 100% rename from patches/server/0243-Use-a-Queue-for-Queueing-Commands.patch rename to patches/server/0237-Use-a-Queue-for-Queueing-Commands.patch diff --git a/patches/server/0244-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch b/patches/server/0238-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch similarity index 100% rename from patches/server/0244-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch rename to patches/server/0238-Ability-to-get-Tile-Entities-from-a-chunk-without-sn.patch diff --git a/patches/server/0245-Optimize-BlockPosition-helper-methods.patch b/patches/server/0239-Optimize-BlockPosition-helper-methods.patch similarity index 100% rename from patches/server/0245-Optimize-BlockPosition-helper-methods.patch rename to patches/server/0239-Optimize-BlockPosition-helper-methods.patch diff --git a/patches/server/0246-Restore-vanilla-default-mob-spawn-range-and-water-an.patch b/patches/server/0240-Restore-vanilla-default-mob-spawn-range-and-water-an.patch similarity index 100% rename from patches/server/0246-Restore-vanilla-default-mob-spawn-range-and-water-an.patch rename to patches/server/0240-Restore-vanilla-default-mob-spawn-range-and-water-an.patch diff --git a/patches/server/0247-Slime-Pathfinder-Events.patch b/patches/server/0241-Slime-Pathfinder-Events.patch similarity index 100% rename from patches/server/0247-Slime-Pathfinder-Events.patch rename to patches/server/0241-Slime-Pathfinder-Events.patch diff --git a/patches/server/0248-Configurable-speed-for-water-flowing-over-lava.patch b/patches/server/0242-Configurable-speed-for-water-flowing-over-lava.patch similarity index 100% rename from patches/server/0248-Configurable-speed-for-water-flowing-over-lava.patch rename to patches/server/0242-Configurable-speed-for-water-flowing-over-lava.patch diff --git a/patches/server/0249-Optimize-CraftBlockData-Creation.patch b/patches/server/0243-Optimize-CraftBlockData-Creation.patch similarity index 100% rename from patches/server/0249-Optimize-CraftBlockData-Creation.patch rename to patches/server/0243-Optimize-CraftBlockData-Creation.patch diff --git a/patches/server/0250-Optimize-MappedRegistry.patch b/patches/server/0244-Optimize-MappedRegistry.patch similarity index 100% rename from patches/server/0250-Optimize-MappedRegistry.patch rename to patches/server/0244-Optimize-MappedRegistry.patch diff --git a/patches/server/0251-Add-PhantomPreSpawnEvent.patch b/patches/server/0245-Add-PhantomPreSpawnEvent.patch similarity index 100% rename from patches/server/0251-Add-PhantomPreSpawnEvent.patch rename to patches/server/0245-Add-PhantomPreSpawnEvent.patch diff --git a/patches/server/0252-Add-More-Creeper-API.patch b/patches/server/0246-Add-More-Creeper-API.patch similarity index 100% rename from patches/server/0252-Add-More-Creeper-API.patch rename to patches/server/0246-Add-More-Creeper-API.patch diff --git a/patches/server/0253-Inventory-removeItemAnySlot.patch b/patches/server/0247-Inventory-removeItemAnySlot.patch similarity index 100% rename from patches/server/0253-Inventory-removeItemAnySlot.patch rename to patches/server/0247-Inventory-removeItemAnySlot.patch diff --git a/patches/server/0254-Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch b/patches/server/0248-Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch similarity index 100% rename from patches/server/0254-Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch rename to patches/server/0248-Make-CraftWorld-loadChunk-int-int-false-load-unconve.patch diff --git a/patches/server/0255-Add-ray-tracing-methods-to-LivingEntity.patch b/patches/server/0249-Add-ray-tracing-methods-to-LivingEntity.patch similarity index 100% rename from patches/server/0255-Add-ray-tracing-methods-to-LivingEntity.patch rename to patches/server/0249-Add-ray-tracing-methods-to-LivingEntity.patch diff --git a/patches/server/0256-Expose-attack-cooldown-methods-for-Player.patch b/patches/server/0250-Expose-attack-cooldown-methods-for-Player.patch similarity index 100% rename from patches/server/0256-Expose-attack-cooldown-methods-for-Player.patch rename to patches/server/0250-Expose-attack-cooldown-methods-for-Player.patch diff --git a/patches/server/0257-Improve-death-events.patch b/patches/server/0251-Improve-death-events.patch similarity index 100% rename from patches/server/0257-Improve-death-events.patch rename to patches/server/0251-Improve-death-events.patch diff --git a/patches/server/0258-Allow-chests-to-be-placed-with-NBT-data.patch b/patches/server/0252-Allow-chests-to-be-placed-with-NBT-data.patch similarity index 100% rename from patches/server/0258-Allow-chests-to-be-placed-with-NBT-data.patch rename to patches/server/0252-Allow-chests-to-be-placed-with-NBT-data.patch diff --git a/patches/server/0259-Mob-Pathfinding-API.patch b/patches/server/0253-Mob-Pathfinding-API.patch similarity index 100% rename from patches/server/0259-Mob-Pathfinding-API.patch rename to patches/server/0253-Mob-Pathfinding-API.patch diff --git a/patches/server/0260-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch b/patches/server/0254-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch similarity index 100% rename from patches/server/0260-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch rename to patches/server/0254-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch diff --git a/patches/server/0261-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch b/patches/server/0255-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch similarity index 100% rename from patches/server/0261-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch rename to patches/server/0255-Prevent-Mob-AI-Rules-from-Loading-Chunks.patch diff --git a/patches/server/0262-Prevent-mob-spawning-from-loading-generating-chunks.patch b/patches/server/0256-Prevent-mob-spawning-from-loading-generating-chunks.patch similarity index 100% rename from patches/server/0262-Prevent-mob-spawning-from-loading-generating-chunks.patch rename to patches/server/0256-Prevent-mob-spawning-from-loading-generating-chunks.patch diff --git a/patches/server/0263-Implement-furnace-cook-speed-multiplier-API.patch b/patches/server/0257-Implement-furnace-cook-speed-multiplier-API.patch similarity index 100% rename from patches/server/0263-Implement-furnace-cook-speed-multiplier-API.patch rename to patches/server/0257-Implement-furnace-cook-speed-multiplier-API.patch diff --git a/patches/server/0264-Honor-EntityAgeable.ageLock.patch b/patches/server/0258-Honor-EntityAgeable.ageLock.patch similarity index 100% rename from patches/server/0264-Honor-EntityAgeable.ageLock.patch rename to patches/server/0258-Honor-EntityAgeable.ageLock.patch diff --git a/patches/server/0265-Configurable-connection-throttle-kick-message.patch b/patches/server/0259-Configurable-connection-throttle-kick-message.patch similarity index 100% rename from patches/server/0265-Configurable-connection-throttle-kick-message.patch rename to patches/server/0259-Configurable-connection-throttle-kick-message.patch diff --git a/patches/server/0266-Hook-into-CB-plugin-rewrites.patch b/patches/server/0260-Hook-into-CB-plugin-rewrites.patch similarity index 100% rename from patches/server/0266-Hook-into-CB-plugin-rewrites.patch rename to patches/server/0260-Hook-into-CB-plugin-rewrites.patch diff --git a/patches/server/0267-PreSpawnerSpawnEvent.patch b/patches/server/0261-PreSpawnerSpawnEvent.patch similarity index 100% rename from patches/server/0267-PreSpawnerSpawnEvent.patch rename to patches/server/0261-PreSpawnerSpawnEvent.patch diff --git a/patches/server/0268-Add-LivingEntity-getTargetEntity.patch b/patches/server/0262-Add-LivingEntity-getTargetEntity.patch similarity index 100% rename from patches/server/0268-Add-LivingEntity-getTargetEntity.patch rename to patches/server/0262-Add-LivingEntity-getTargetEntity.patch diff --git a/patches/server/0269-Add-sun-related-API.patch b/patches/server/0263-Add-sun-related-API.patch similarity index 100% rename from patches/server/0269-Add-sun-related-API.patch rename to patches/server/0263-Add-sun-related-API.patch diff --git a/patches/server/0270-Turtle-API.patch b/patches/server/0264-Turtle-API.patch similarity index 100% rename from patches/server/0270-Turtle-API.patch rename to patches/server/0264-Turtle-API.patch diff --git a/patches/server/0271-Call-player-spectator-target-events-and-improve-impl.patch b/patches/server/0265-Call-player-spectator-target-events-and-improve-impl.patch similarity index 100% rename from patches/server/0271-Call-player-spectator-target-events-and-improve-impl.patch rename to patches/server/0265-Call-player-spectator-target-events-and-improve-impl.patch diff --git a/patches/server/0272-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch b/patches/server/0266-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch similarity index 100% rename from patches/server/0272-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch rename to patches/server/0266-MC-50319-Check-other-worlds-for-shooter-of-projectil.patch diff --git a/patches/server/0273-Add-more-Witch-API.patch b/patches/server/0267-Add-more-Witch-API.patch similarity index 100% rename from patches/server/0273-Add-more-Witch-API.patch rename to patches/server/0267-Add-more-Witch-API.patch diff --git a/patches/server/0274-Check-Drowned-for-Villager-Aggression-Config.patch b/patches/server/0268-Check-Drowned-for-Villager-Aggression-Config.patch similarity index 100% rename from patches/server/0274-Check-Drowned-for-Villager-Aggression-Config.patch rename to patches/server/0268-Check-Drowned-for-Villager-Aggression-Config.patch diff --git a/patches/server/0275-Add-option-to-prevent-players-from-moving-into-unloa.patch b/patches/server/0269-Add-option-to-prevent-players-from-moving-into-unloa.patch similarity index 100% rename from patches/server/0275-Add-option-to-prevent-players-from-moving-into-unloa.patch rename to patches/server/0269-Add-option-to-prevent-players-from-moving-into-unloa.patch diff --git a/patches/server/0276-Reset-players-airTicks-on-respawn.patch b/patches/server/0270-Reset-players-airTicks-on-respawn.patch similarity index 100% rename from patches/server/0276-Reset-players-airTicks-on-respawn.patch rename to patches/server/0270-Reset-players-airTicks-on-respawn.patch diff --git a/patches/server/0277-Don-t-sleep-after-profile-lookups-if-not-needed.patch b/patches/server/0271-Don-t-sleep-after-profile-lookups-if-not-needed.patch similarity index 100% rename from patches/server/0277-Don-t-sleep-after-profile-lookups-if-not-needed.patch rename to patches/server/0271-Don-t-sleep-after-profile-lookups-if-not-needed.patch diff --git a/patches/server/0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch b/patches/server/0272-Improve-Server-Thread-Pool-and-Thread-Priorities.patch similarity index 100% rename from patches/server/0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch rename to patches/server/0272-Improve-Server-Thread-Pool-and-Thread-Priorities.patch diff --git a/patches/server/0279-Optimize-World-Time-Updates.patch b/patches/server/0273-Optimize-World-Time-Updates.patch similarity index 100% rename from patches/server/0279-Optimize-World-Time-Updates.patch rename to patches/server/0273-Optimize-World-Time-Updates.patch diff --git a/patches/server/0280-Restore-custom-InventoryHolder-support.patch b/patches/server/0274-Restore-custom-InventoryHolder-support.patch similarity index 100% rename from patches/server/0280-Restore-custom-InventoryHolder-support.patch rename to patches/server/0274-Restore-custom-InventoryHolder-support.patch diff --git a/patches/server/0281-Use-Vanilla-Minecart-Speeds.patch b/patches/server/0275-Use-Vanilla-Minecart-Speeds.patch similarity index 100% rename from patches/server/0281-Use-Vanilla-Minecart-Speeds.patch rename to patches/server/0275-Use-Vanilla-Minecart-Speeds.patch diff --git a/patches/server/0282-Fix-SpongeAbsortEvent-handling.patch b/patches/server/0276-Fix-SpongeAbsortEvent-handling.patch similarity index 100% rename from patches/server/0282-Fix-SpongeAbsortEvent-handling.patch rename to patches/server/0276-Fix-SpongeAbsortEvent-handling.patch diff --git a/patches/server/0283-Don-t-allow-digging-into-unloaded-chunks.patch b/patches/server/0277-Don-t-allow-digging-into-unloaded-chunks.patch similarity index 100% rename from patches/server/0283-Don-t-allow-digging-into-unloaded-chunks.patch rename to patches/server/0277-Don-t-allow-digging-into-unloaded-chunks.patch diff --git a/patches/server/0284-Make-the-default-permission-message-configurable.patch b/patches/server/0278-Make-the-default-permission-message-configurable.patch similarity index 100% rename from patches/server/0284-Make-the-default-permission-message-configurable.patch rename to patches/server/0278-Make-the-default-permission-message-configurable.patch diff --git a/patches/server/0285-Prevent-rayTrace-from-loading-chunks.patch b/patches/server/0279-Prevent-rayTrace-from-loading-chunks.patch similarity index 100% rename from patches/server/0285-Prevent-rayTrace-from-loading-chunks.patch rename to patches/server/0279-Prevent-rayTrace-from-loading-chunks.patch diff --git a/patches/server/0286-Handle-Large-Packets-disconnecting-client.patch b/patches/server/0280-Handle-Large-Packets-disconnecting-client.patch similarity index 100% rename from patches/server/0286-Handle-Large-Packets-disconnecting-client.patch rename to patches/server/0280-Handle-Large-Packets-disconnecting-client.patch diff --git a/patches/server/0287-force-entity-dismount-during-teleportation.patch b/patches/server/0281-force-entity-dismount-during-teleportation.patch similarity index 100% rename from patches/server/0287-force-entity-dismount-during-teleportation.patch rename to patches/server/0281-force-entity-dismount-during-teleportation.patch diff --git a/patches/server/0288-Add-more-Zombie-API.patch b/patches/server/0282-Add-more-Zombie-API.patch similarity index 100% rename from patches/server/0288-Add-more-Zombie-API.patch rename to patches/server/0282-Add-more-Zombie-API.patch diff --git a/patches/server/0289-Book-Size-Limits.patch b/patches/server/0283-Book-Size-Limits.patch similarity index 100% rename from patches/server/0289-Book-Size-Limits.patch rename to patches/server/0283-Book-Size-Limits.patch diff --git a/patches/server/0290-Add-PlayerConnectionCloseEvent.patch b/patches/server/0284-Add-PlayerConnectionCloseEvent.patch similarity index 100% rename from patches/server/0290-Add-PlayerConnectionCloseEvent.patch rename to patches/server/0284-Add-PlayerConnectionCloseEvent.patch diff --git a/patches/server/0291-Prevent-Enderman-from-loading-chunks.patch b/patches/server/0285-Prevent-Enderman-from-loading-chunks.patch similarity index 100% rename from patches/server/0291-Prevent-Enderman-from-loading-chunks.patch rename to patches/server/0285-Prevent-Enderman-from-loading-chunks.patch diff --git a/patches/server/0292-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch b/patches/server/0286-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch similarity index 100% rename from patches/server/0292-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch rename to patches/server/0286-Add-APIs-to-replace-OfflinePlayer-getLastPlayed.patch diff --git a/patches/server/0293-Workaround-for-vehicle-tracking-issue-on-disconnect.patch b/patches/server/0287-Workaround-for-vehicle-tracking-issue-on-disconnect.patch similarity index 100% rename from patches/server/0293-Workaround-for-vehicle-tracking-issue-on-disconnect.patch rename to patches/server/0287-Workaround-for-vehicle-tracking-issue-on-disconnect.patch diff --git a/patches/server/0294-Block-Entity-remove-from-being-called-on-Players.patch b/patches/server/0288-Block-Entity-remove-from-being-called-on-Players.patch similarity index 100% rename from patches/server/0294-Block-Entity-remove-from-being-called-on-Players.patch rename to patches/server/0288-Block-Entity-remove-from-being-called-on-Players.patch diff --git a/patches/server/0295-BlockDestroyEvent.patch b/patches/server/0289-BlockDestroyEvent.patch similarity index 100% rename from patches/server/0295-BlockDestroyEvent.patch rename to patches/server/0289-BlockDestroyEvent.patch diff --git a/patches/server/0296-Async-command-map-building.patch b/patches/server/0290-Async-command-map-building.patch similarity index 100% rename from patches/server/0296-Async-command-map-building.patch rename to patches/server/0290-Async-command-map-building.patch diff --git a/patches/server/0297-Implement-Brigadier-Mojang-API.patch b/patches/server/0291-Implement-Brigadier-Mojang-API.patch similarity index 100% rename from patches/server/0297-Implement-Brigadier-Mojang-API.patch rename to patches/server/0291-Implement-Brigadier-Mojang-API.patch diff --git a/patches/server/0298-Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch b/patches/server/0292-Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch similarity index 100% rename from patches/server/0298-Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch rename to patches/server/0292-Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch diff --git a/patches/server/0299-Limit-Client-Sign-length-more.patch b/patches/server/0293-Limit-Client-Sign-length-more.patch similarity index 100% rename from patches/server/0299-Limit-Client-Sign-length-more.patch rename to patches/server/0293-Limit-Client-Sign-length-more.patch diff --git a/patches/server/0300-Handle-Oversized-Tile-Entities-in-chunks.patch b/patches/server/0294-Handle-Oversized-Tile-Entities-in-chunks.patch similarity index 100% rename from patches/server/0300-Handle-Oversized-Tile-Entities-in-chunks.patch rename to patches/server/0294-Handle-Oversized-Tile-Entities-in-chunks.patch diff --git a/patches/server/0301-Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch b/patches/server/0295-Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch similarity index 100% rename from patches/server/0301-Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch rename to patches/server/0295-Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch diff --git a/patches/server/0302-Entity-getEntitySpawnReason.patch b/patches/server/0296-Entity-getEntitySpawnReason.patch similarity index 100% rename from patches/server/0302-Entity-getEntitySpawnReason.patch rename to patches/server/0296-Entity-getEntitySpawnReason.patch diff --git a/patches/server/0303-Fire-event-on-GS4-query.patch b/patches/server/0297-Fire-event-on-GS4-query.patch similarity index 100% rename from patches/server/0303-Fire-event-on-GS4-query.patch rename to patches/server/0297-Fire-event-on-GS4-query.patch diff --git a/patches/server/0304-Implement-PlayerPostRespawnEvent.patch b/patches/server/0298-Implement-PlayerPostRespawnEvent.patch similarity index 100% rename from patches/server/0304-Implement-PlayerPostRespawnEvent.patch rename to patches/server/0298-Implement-PlayerPostRespawnEvent.patch diff --git a/patches/server/0305-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch b/patches/server/0299-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch similarity index 100% rename from patches/server/0305-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch rename to patches/server/0299-don-t-go-below-0-for-pickupDelay-breaks-picking-up-i.patch diff --git a/patches/server/0306-Server-Tick-Events.patch b/patches/server/0300-Server-Tick-Events.patch similarity index 100% rename from patches/server/0306-Server-Tick-Events.patch rename to patches/server/0300-Server-Tick-Events.patch diff --git a/patches/server/0307-PlayerDeathEvent-getItemsToKeep.patch b/patches/server/0301-PlayerDeathEvent-getItemsToKeep.patch similarity index 100% rename from patches/server/0307-PlayerDeathEvent-getItemsToKeep.patch rename to patches/server/0301-PlayerDeathEvent-getItemsToKeep.patch diff --git a/patches/server/0308-Optimize-Captured-TileEntity-Lookup.patch b/patches/server/0302-Optimize-Captured-TileEntity-Lookup.patch similarity index 100% rename from patches/server/0308-Optimize-Captured-TileEntity-Lookup.patch rename to patches/server/0302-Optimize-Captured-TileEntity-Lookup.patch diff --git a/patches/server/0309-Add-Heightmap-API.patch b/patches/server/0303-Add-Heightmap-API.patch similarity index 100% rename from patches/server/0309-Add-Heightmap-API.patch rename to patches/server/0303-Add-Heightmap-API.patch diff --git a/patches/server/0310-Mob-Spawner-API-Enhancements.patch b/patches/server/0304-Mob-Spawner-API-Enhancements.patch similarity index 100% rename from patches/server/0310-Mob-Spawner-API-Enhancements.patch rename to patches/server/0304-Mob-Spawner-API-Enhancements.patch diff --git a/patches/server/0311-Fix-CB-call-to-changed-postToMainThread-method.patch b/patches/server/0305-Fix-CB-call-to-changed-postToMainThread-method.patch similarity index 100% rename from patches/server/0311-Fix-CB-call-to-changed-postToMainThread-method.patch rename to patches/server/0305-Fix-CB-call-to-changed-postToMainThread-method.patch diff --git a/patches/server/0312-Fix-sounds-when-item-frames-are-modified-MC-123450.patch b/patches/server/0306-Fix-sounds-when-item-frames-are-modified-MC-123450.patch similarity index 100% rename from patches/server/0312-Fix-sounds-when-item-frames-are-modified-MC-123450.patch rename to patches/server/0306-Fix-sounds-when-item-frames-are-modified-MC-123450.patch diff --git a/patches/server/0313-Implement-CraftBlockSoundGroup.patch b/patches/server/0307-Implement-CraftBlockSoundGroup.patch similarity index 100% rename from patches/server/0313-Implement-CraftBlockSoundGroup.patch rename to patches/server/0307-Implement-CraftBlockSoundGroup.patch diff --git a/patches/server/0314-Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/0308-Configurable-Keep-Spawn-Loaded-range-per-world.patch similarity index 100% rename from patches/server/0314-Configurable-Keep-Spawn-Loaded-range-per-world.patch rename to patches/server/0308-Configurable-Keep-Spawn-Loaded-range-per-world.patch diff --git a/patches/server/0315-Allow-Saving-of-Oversized-Chunks.patch b/patches/server/0309-Allow-Saving-of-Oversized-Chunks.patch similarity index 100% rename from patches/server/0315-Allow-Saving-of-Oversized-Chunks.patch rename to patches/server/0309-Allow-Saving-of-Oversized-Chunks.patch diff --git a/patches/server/0316-Expose-the-internal-current-tick.patch b/patches/server/0310-Expose-the-internal-current-tick.patch similarity index 100% rename from patches/server/0316-Expose-the-internal-current-tick.patch rename to patches/server/0310-Expose-the-internal-current-tick.patch diff --git a/patches/server/0317-Fix-World-isChunkGenerated-calls.patch b/patches/server/0311-Fix-World-isChunkGenerated-calls.patch similarity index 100% rename from patches/server/0317-Fix-World-isChunkGenerated-calls.patch rename to patches/server/0311-Fix-World-isChunkGenerated-calls.patch diff --git a/patches/server/0318-Show-blockstate-location-if-we-failed-to-read-it.patch b/patches/server/0312-Show-blockstate-location-if-we-failed-to-read-it.patch similarity index 100% rename from patches/server/0318-Show-blockstate-location-if-we-failed-to-read-it.patch rename to patches/server/0312-Show-blockstate-location-if-we-failed-to-read-it.patch diff --git a/patches/server/0319-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch b/patches/server/0313-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch similarity index 100% rename from patches/server/0319-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch rename to patches/server/0313-Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch diff --git a/patches/server/0320-Configurable-projectile-relative-velocity.patch b/patches/server/0314-Configurable-projectile-relative-velocity.patch similarity index 100% rename from patches/server/0320-Configurable-projectile-relative-velocity.patch rename to patches/server/0314-Configurable-projectile-relative-velocity.patch diff --git a/patches/server/0321-offset-item-frame-ticking.patch b/patches/server/0315-offset-item-frame-ticking.patch similarity index 100% rename from patches/server/0321-offset-item-frame-ticking.patch rename to patches/server/0315-offset-item-frame-ticking.patch diff --git a/patches/server/0322-Fix-MC-158900.patch b/patches/server/0316-Fix-MC-158900.patch similarity index 100% rename from patches/server/0322-Fix-MC-158900.patch rename to patches/server/0316-Fix-MC-158900.patch diff --git a/patches/server/0323-Prevent-consuming-the-wrong-itemstack.patch b/patches/server/0317-Prevent-consuming-the-wrong-itemstack.patch similarity index 100% rename from patches/server/0323-Prevent-consuming-the-wrong-itemstack.patch rename to patches/server/0317-Prevent-consuming-the-wrong-itemstack.patch diff --git a/patches/server/0324-Dont-send-unnecessary-sign-update.patch b/patches/server/0318-Dont-send-unnecessary-sign-update.patch similarity index 100% rename from patches/server/0324-Dont-send-unnecessary-sign-update.patch rename to patches/server/0318-Dont-send-unnecessary-sign-update.patch diff --git a/patches/server/0325-Add-option-to-disable-pillager-patrols.patch b/patches/server/0319-Add-option-to-disable-pillager-patrols.patch similarity index 100% rename from patches/server/0325-Add-option-to-disable-pillager-patrols.patch rename to patches/server/0319-Add-option-to-disable-pillager-patrols.patch diff --git a/patches/server/0326-Flat-bedrock-generator-settings.patch b/patches/server/0320-Flat-bedrock-generator-settings.patch similarity index 100% rename from patches/server/0326-Flat-bedrock-generator-settings.patch rename to patches/server/0320-Flat-bedrock-generator-settings.patch diff --git a/patches/server/0327-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch b/patches/server/0321-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch similarity index 100% rename from patches/server/0327-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch rename to patches/server/0321-Prevent-sync-chunk-loads-when-villagers-try-to-find-.patch diff --git a/patches/server/0328-MC-145656-Fix-Follow-Range-Initial-Target.patch b/patches/server/0322-MC-145656-Fix-Follow-Range-Initial-Target.patch similarity index 100% rename from patches/server/0328-MC-145656-Fix-Follow-Range-Initial-Target.patch rename to patches/server/0322-MC-145656-Fix-Follow-Range-Initial-Target.patch diff --git a/patches/server/0329-Duplicate-UUID-Resolve-Option.patch b/patches/server/0323-Duplicate-UUID-Resolve-Option.patch similarity index 100% rename from patches/server/0329-Duplicate-UUID-Resolve-Option.patch rename to patches/server/0323-Duplicate-UUID-Resolve-Option.patch diff --git a/patches/server/0330-PlayerDeathEvent-shouldDropExperience.patch b/patches/server/0324-PlayerDeathEvent-shouldDropExperience.patch similarity index 100% rename from patches/server/0330-PlayerDeathEvent-shouldDropExperience.patch rename to patches/server/0324-PlayerDeathEvent-shouldDropExperience.patch diff --git a/patches/server/0331-Prevent-bees-loading-chunks-checking-hive-position.patch b/patches/server/0325-Prevent-bees-loading-chunks-checking-hive-position.patch similarity index 100% rename from patches/server/0331-Prevent-bees-loading-chunks-checking-hive-position.patch rename to patches/server/0325-Prevent-bees-loading-chunks-checking-hive-position.patch diff --git a/patches/server/0332-Don-t-load-Chunks-from-Hoppers-and-other-things.patch b/patches/server/0326-Don-t-load-Chunks-from-Hoppers-and-other-things.patch similarity index 100% rename from patches/server/0332-Don-t-load-Chunks-from-Hoppers-and-other-things.patch rename to patches/server/0326-Don-t-load-Chunks-from-Hoppers-and-other-things.patch diff --git a/patches/server/0333-Optimise-EntityGetter-getPlayerByUUID.patch b/patches/server/0327-Optimise-EntityGetter-getPlayerByUUID.patch similarity index 100% rename from patches/server/0333-Optimise-EntityGetter-getPlayerByUUID.patch rename to patches/server/0327-Optimise-EntityGetter-getPlayerByUUID.patch diff --git a/patches/server/0334-Fix-items-not-falling-correctly.patch b/patches/server/0328-Fix-items-not-falling-correctly.patch similarity index 100% rename from patches/server/0334-Fix-items-not-falling-correctly.patch rename to patches/server/0328-Fix-items-not-falling-correctly.patch diff --git a/patches/server/0335-Optimize-call-to-getFluid-for-explosions.patch b/patches/server/0329-Optimize-call-to-getFluid-for-explosions.patch similarity index 100% rename from patches/server/0335-Optimize-call-to-getFluid-for-explosions.patch rename to patches/server/0329-Optimize-call-to-getFluid-for-explosions.patch diff --git a/patches/server/0336-Fix-last-firework-in-stack-not-having-effects-when-d.patch b/patches/server/0330-Fix-last-firework-in-stack-not-having-effects-when-d.patch similarity index 100% rename from patches/server/0336-Fix-last-firework-in-stack-not-having-effects-when-d.patch rename to patches/server/0330-Fix-last-firework-in-stack-not-having-effects-when-d.patch diff --git a/patches/server/0337-Entity-Activation-Range-2.0.patch b/patches/server/0331-Entity-Activation-Range-2.0.patch similarity index 100% rename from patches/server/0337-Entity-Activation-Range-2.0.patch rename to patches/server/0331-Entity-Activation-Range-2.0.patch diff --git a/patches/server/0338-Implement-alternative-item-despawn-rate.patch b/patches/server/0332-Implement-alternative-item-despawn-rate.patch similarity index 100% rename from patches/server/0338-Implement-alternative-item-despawn-rate.patch rename to patches/server/0332-Implement-alternative-item-despawn-rate.patch diff --git a/patches/server/0339-Tracking-Range-Improvements.patch b/patches/server/0333-Tracking-Range-Improvements.patch similarity index 100% rename from patches/server/0339-Tracking-Range-Improvements.patch rename to patches/server/0333-Tracking-Range-Improvements.patch diff --git a/patches/server/0340-Fix-items-vanishing-through-end-portal.patch b/patches/server/0334-Fix-items-vanishing-through-end-portal.patch similarity index 100% rename from patches/server/0340-Fix-items-vanishing-through-end-portal.patch rename to patches/server/0334-Fix-items-vanishing-through-end-portal.patch diff --git a/patches/server/0341-implement-optional-per-player-mob-spawns.patch b/patches/server/0335-implement-optional-per-player-mob-spawns.patch similarity index 100% rename from patches/server/0341-implement-optional-per-player-mob-spawns.patch rename to patches/server/0335-implement-optional-per-player-mob-spawns.patch diff --git a/patches/server/0342-Bees-get-gravity-in-void.-Fixes-MC-167279.patch b/patches/server/0336-Bees-get-gravity-in-void.-Fixes-MC-167279.patch similarity index 100% rename from patches/server/0342-Bees-get-gravity-in-void.-Fixes-MC-167279.patch rename to patches/server/0336-Bees-get-gravity-in-void.-Fixes-MC-167279.patch diff --git a/patches/server/0343-Improve-Block-breakNaturally-API.patch b/patches/server/0337-Improve-Block-breakNaturally-API.patch similarity index 100% rename from patches/server/0343-Improve-Block-breakNaturally-API.patch rename to patches/server/0337-Improve-Block-breakNaturally-API.patch diff --git a/patches/server/0344-Optimise-getChunkAt-calls-for-loaded-chunks.patch b/patches/server/0338-Optimise-getChunkAt-calls-for-loaded-chunks.patch similarity index 100% rename from patches/server/0344-Optimise-getChunkAt-calls-for-loaded-chunks.patch rename to patches/server/0338-Optimise-getChunkAt-calls-for-loaded-chunks.patch diff --git a/patches/server/0345-Add-debug-for-sync-chunk-loads.patch b/patches/server/0339-Add-debug-for-sync-chunk-loads.patch similarity index 100% rename from patches/server/0345-Add-debug-for-sync-chunk-loads.patch rename to patches/server/0339-Add-debug-for-sync-chunk-loads.patch diff --git a/patches/server/0346-Remove-garbage-Java-version-check.patch b/patches/server/0340-Remove-garbage-Java-version-check.patch similarity index 100% rename from patches/server/0346-Remove-garbage-Java-version-check.patch rename to patches/server/0340-Remove-garbage-Java-version-check.patch diff --git a/patches/server/0347-Add-ThrownEggHatchEvent.patch b/patches/server/0341-Add-ThrownEggHatchEvent.patch similarity index 100% rename from patches/server/0347-Add-ThrownEggHatchEvent.patch rename to patches/server/0341-Add-ThrownEggHatchEvent.patch diff --git a/patches/server/0348-Entity-Jump-API.patch b/patches/server/0342-Entity-Jump-API.patch similarity index 100% rename from patches/server/0348-Entity-Jump-API.patch rename to patches/server/0342-Entity-Jump-API.patch diff --git a/patches/server/0349-Add-option-to-nerf-pigmen-from-nether-portals.patch b/patches/server/0343-Add-option-to-nerf-pigmen-from-nether-portals.patch similarity index 100% rename from patches/server/0349-Add-option-to-nerf-pigmen-from-nether-portals.patch rename to patches/server/0343-Add-option-to-nerf-pigmen-from-nether-portals.patch diff --git a/patches/server/0350-Make-the-GUI-graph-fancier.patch b/patches/server/0344-Make-the-GUI-graph-fancier.patch similarity index 100% rename from patches/server/0350-Make-the-GUI-graph-fancier.patch rename to patches/server/0344-Make-the-GUI-graph-fancier.patch diff --git a/patches/server/0351-add-hand-to-BlockMultiPlaceEvent.patch b/patches/server/0345-add-hand-to-BlockMultiPlaceEvent.patch similarity index 100% rename from patches/server/0351-add-hand-to-BlockMultiPlaceEvent.patch rename to patches/server/0345-add-hand-to-BlockMultiPlaceEvent.patch diff --git a/patches/server/0352-Validate-tripwire-hook-placement-before-update.patch b/patches/server/0346-Validate-tripwire-hook-placement-before-update.patch similarity index 100% rename from patches/server/0352-Validate-tripwire-hook-placement-before-update.patch rename to patches/server/0346-Validate-tripwire-hook-placement-before-update.patch diff --git a/patches/server/0353-Add-option-to-allow-iron-golems-to-spawn-in-air.patch b/patches/server/0347-Add-option-to-allow-iron-golems-to-spawn-in-air.patch similarity index 100% rename from patches/server/0353-Add-option-to-allow-iron-golems-to-spawn-in-air.patch rename to patches/server/0347-Add-option-to-allow-iron-golems-to-spawn-in-air.patch diff --git a/patches/server/0354-Configurable-chance-of-villager-zombie-infection.patch b/patches/server/0348-Configurable-chance-of-villager-zombie-infection.patch similarity index 100% rename from patches/server/0354-Configurable-chance-of-villager-zombie-infection.patch rename to patches/server/0348-Configurable-chance-of-villager-zombie-infection.patch diff --git a/patches/server/0355-Optimise-Chunk-getFluid.patch b/patches/server/0349-Optimise-Chunk-getFluid.patch similarity index 100% rename from patches/server/0355-Optimise-Chunk-getFluid.patch rename to patches/server/0349-Optimise-Chunk-getFluid.patch diff --git a/patches/server/0356-Set-spigots-verbose-world-setting-to-false-by-def.patch b/patches/server/0350-Set-spigots-verbose-world-setting-to-false-by-def.patch similarity index 100% rename from patches/server/0356-Set-spigots-verbose-world-setting-to-false-by-def.patch rename to patches/server/0350-Set-spigots-verbose-world-setting-to-false-by-def.patch diff --git a/patches/server/0357-Add-tick-times-API-and-mspt-command.patch b/patches/server/0351-Add-tick-times-API-and-mspt-command.patch similarity index 100% rename from patches/server/0357-Add-tick-times-API-and-mspt-command.patch rename to patches/server/0351-Add-tick-times-API-and-mspt-command.patch diff --git a/patches/server/0358-Expose-MinecraftServer-isRunning.patch b/patches/server/0352-Expose-MinecraftServer-isRunning.patch similarity index 100% rename from patches/server/0358-Expose-MinecraftServer-isRunning.patch rename to patches/server/0352-Expose-MinecraftServer-isRunning.patch diff --git a/patches/server/0359-Add-Raw-Byte-ItemStack-Serialization.patch b/patches/server/0353-Add-Raw-Byte-ItemStack-Serialization.patch similarity index 100% rename from patches/server/0359-Add-Raw-Byte-ItemStack-Serialization.patch rename to patches/server/0353-Add-Raw-Byte-ItemStack-Serialization.patch diff --git a/patches/server/0360-Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/0354-Pillager-patrol-spawn-settings-and-per-player-option.patch similarity index 100% rename from patches/server/0360-Pillager-patrol-spawn-settings-and-per-player-option.patch rename to patches/server/0354-Pillager-patrol-spawn-settings-and-per-player-option.patch diff --git a/patches/server/0361-Remote-Connections-shouldn-t-hold-up-shutdown.patch b/patches/server/0355-Remote-Connections-shouldn-t-hold-up-shutdown.patch similarity index 100% rename from patches/server/0361-Remote-Connections-shouldn-t-hold-up-shutdown.patch rename to patches/server/0355-Remote-Connections-shouldn-t-hold-up-shutdown.patch diff --git a/patches/server/0362-Do-not-allow-bees-to-load-chunks-for-beehives.patch b/patches/server/0356-Do-not-allow-bees-to-load-chunks-for-beehives.patch similarity index 100% rename from patches/server/0362-Do-not-allow-bees-to-load-chunks-for-beehives.patch rename to patches/server/0356-Do-not-allow-bees-to-load-chunks-for-beehives.patch diff --git a/patches/server/0363-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch b/patches/server/0357-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch similarity index 100% rename from patches/server/0363-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch rename to patches/server/0357-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch diff --git a/patches/server/0364-Don-t-tick-dead-players.patch b/patches/server/0358-Don-t-tick-dead-players.patch similarity index 100% rename from patches/server/0364-Don-t-tick-dead-players.patch rename to patches/server/0358-Don-t-tick-dead-players.patch diff --git a/patches/server/0365-Dead-Player-s-shouldn-t-be-able-to-move.patch b/patches/server/0359-Dead-Player-s-shouldn-t-be-able-to-move.patch similarity index 100% rename from patches/server/0365-Dead-Player-s-shouldn-t-be-able-to-move.patch rename to patches/server/0359-Dead-Player-s-shouldn-t-be-able-to-move.patch diff --git a/patches/server/0366-Optimize-Collision-to-not-load-chunks.patch b/patches/server/0360-Optimize-Collision-to-not-load-chunks.patch similarity index 100% rename from patches/server/0366-Optimize-Collision-to-not-load-chunks.patch rename to patches/server/0360-Optimize-Collision-to-not-load-chunks.patch diff --git a/patches/server/0367-Don-t-move-existing-players-to-world-spawn.patch b/patches/server/0361-Don-t-move-existing-players-to-world-spawn.patch similarity index 100% rename from patches/server/0367-Don-t-move-existing-players-to-world-spawn.patch rename to patches/server/0361-Don-t-move-existing-players-to-world-spawn.patch diff --git a/patches/server/0368-Optimize-GoalSelector-Goal.Flag-Set-operations.patch b/patches/server/0362-Optimize-GoalSelector-Goal.Flag-Set-operations.patch similarity index 100% rename from patches/server/0368-Optimize-GoalSelector-Goal.Flag-Set-operations.patch rename to patches/server/0362-Optimize-GoalSelector-Goal.Flag-Set-operations.patch diff --git a/patches/server/0369-Improved-Watchdog-Support.patch b/patches/server/0363-Improved-Watchdog-Support.patch similarity index 100% rename from patches/server/0369-Improved-Watchdog-Support.patch rename to patches/server/0363-Improved-Watchdog-Support.patch diff --git a/patches/server/0370-Optimize-Pathfinding.patch b/patches/server/0364-Optimize-Pathfinding.patch similarity index 100% rename from patches/server/0370-Optimize-Pathfinding.patch rename to patches/server/0364-Optimize-Pathfinding.patch diff --git a/patches/server/0371-Reduce-Either-Optional-allocation.patch b/patches/server/0365-Reduce-Either-Optional-allocation.patch similarity index 100% rename from patches/server/0371-Reduce-Either-Optional-allocation.patch rename to patches/server/0365-Reduce-Either-Optional-allocation.patch diff --git a/patches/server/0372-Reduce-memory-footprint-of-NBTTagCompound.patch b/patches/server/0366-Reduce-memory-footprint-of-NBTTagCompound.patch similarity index 100% rename from patches/server/0372-Reduce-memory-footprint-of-NBTTagCompound.patch rename to patches/server/0366-Reduce-memory-footprint-of-NBTTagCompound.patch diff --git a/patches/server/0373-Prevent-opening-inventories-when-frozen.patch b/patches/server/0367-Prevent-opening-inventories-when-frozen.patch similarity index 100% rename from patches/server/0373-Prevent-opening-inventories-when-frozen.patch rename to patches/server/0367-Prevent-opening-inventories-when-frozen.patch diff --git a/patches/server/0374-Don-t-run-entity-collision-code-if-not-needed.patch b/patches/server/0368-Don-t-run-entity-collision-code-if-not-needed.patch similarity index 100% rename from patches/server/0374-Don-t-run-entity-collision-code-if-not-needed.patch rename to patches/server/0368-Don-t-run-entity-collision-code-if-not-needed.patch diff --git a/patches/server/0375-Implement-Player-Client-Options-API.patch b/patches/server/0369-Implement-Player-Client-Options-API.patch similarity index 100% rename from patches/server/0375-Implement-Player-Client-Options-API.patch rename to patches/server/0369-Implement-Player-Client-Options-API.patch diff --git a/patches/server/0376-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch b/patches/server/0370-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch similarity index 100% rename from patches/server/0376-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch rename to patches/server/0370-Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch diff --git a/patches/server/0377-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch b/patches/server/0371-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch similarity index 100% rename from patches/server/0377-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch rename to patches/server/0371-Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch diff --git a/patches/server/0378-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch b/patches/server/0372-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch similarity index 100% rename from patches/server/0378-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch rename to patches/server/0372-Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch diff --git a/patches/server/0379-Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/server/0373-Add-PlayerAttackEntityCooldownResetEvent.patch similarity index 100% rename from patches/server/0379-Add-PlayerAttackEntityCooldownResetEvent.patch rename to patches/server/0373-Add-PlayerAttackEntityCooldownResetEvent.patch diff --git a/patches/server/0380-Don-t-fire-BlockFade-on-worldgen-threads.patch b/patches/server/0374-Don-t-fire-BlockFade-on-worldgen-threads.patch similarity index 100% rename from patches/server/0380-Don-t-fire-BlockFade-on-worldgen-threads.patch rename to patches/server/0374-Don-t-fire-BlockFade-on-worldgen-threads.patch diff --git a/patches/server/0381-Add-phantom-creative-and-insomniac-controls.patch b/patches/server/0375-Add-phantom-creative-and-insomniac-controls.patch similarity index 100% rename from patches/server/0381-Add-phantom-creative-and-insomniac-controls.patch rename to patches/server/0375-Add-phantom-creative-and-insomniac-controls.patch diff --git a/patches/server/0382-Fix-numerous-item-duplication-issues-and-teleport-is.patch b/patches/server/0376-Fix-numerous-item-duplication-issues-and-teleport-is.patch similarity index 100% rename from patches/server/0382-Fix-numerous-item-duplication-issues-and-teleport-is.patch rename to patches/server/0376-Fix-numerous-item-duplication-issues-and-teleport-is.patch diff --git a/patches/server/0383-Villager-Restocks-API.patch b/patches/server/0377-Villager-Restocks-API.patch similarity index 100% rename from patches/server/0383-Villager-Restocks-API.patch rename to patches/server/0377-Villager-Restocks-API.patch diff --git a/patches/server/0384-Validate-PickItem-Packet-and-kick-for-invalid.patch b/patches/server/0378-Validate-PickItem-Packet-and-kick-for-invalid.patch similarity index 100% rename from patches/server/0384-Validate-PickItem-Packet-and-kick-for-invalid.patch rename to patches/server/0378-Validate-PickItem-Packet-and-kick-for-invalid.patch diff --git a/patches/server/0385-Expose-game-version.patch b/patches/server/0379-Expose-game-version.patch similarity index 100% rename from patches/server/0385-Expose-game-version.patch rename to patches/server/0379-Expose-game-version.patch diff --git a/patches/server/0386-Optimize-Voxel-Shape-Merging.patch b/patches/server/0380-Optimize-Voxel-Shape-Merging.patch similarity index 100% rename from patches/server/0386-Optimize-Voxel-Shape-Merging.patch rename to patches/server/0380-Optimize-Voxel-Shape-Merging.patch diff --git a/patches/server/0387-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch b/patches/server/0381-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch similarity index 100% rename from patches/server/0387-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch rename to patches/server/0381-Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch diff --git a/patches/server/0388-misc-debugging-dumps.patch b/patches/server/0382-misc-debugging-dumps.patch similarity index 100% rename from patches/server/0388-misc-debugging-dumps.patch rename to patches/server/0382-misc-debugging-dumps.patch diff --git a/patches/server/0389-Prevent-teleporting-dead-entities.patch b/patches/server/0383-Prevent-teleporting-dead-entities.patch similarity index 100% rename from patches/server/0389-Prevent-teleporting-dead-entities.patch rename to patches/server/0383-Prevent-teleporting-dead-entities.patch diff --git a/patches/server/0390-Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/0384-Deobfuscate-stacktraces-in-log-messages-crash-report.patch similarity index 100% rename from patches/server/0390-Deobfuscate-stacktraces-in-log-messages-crash-report.patch rename to patches/server/0384-Deobfuscate-stacktraces-in-log-messages-crash-report.patch diff --git a/patches/server/0391-Implement-Mob-Goal-API.patch b/patches/server/0385-Implement-Mob-Goal-API.patch similarity index 100% rename from patches/server/0391-Implement-Mob-Goal-API.patch rename to patches/server/0385-Implement-Mob-Goal-API.patch diff --git a/patches/server/0392-Add-villager-reputation-API.patch b/patches/server/0386-Add-villager-reputation-API.patch similarity index 100% rename from patches/server/0392-Add-villager-reputation-API.patch rename to patches/server/0386-Add-villager-reputation-API.patch diff --git a/patches/server/0393-Option-for-maximum-exp-value-when-merging-orbs.patch b/patches/server/0387-Option-for-maximum-exp-value-when-merging-orbs.patch similarity index 100% rename from patches/server/0393-Option-for-maximum-exp-value-when-merging-orbs.patch rename to patches/server/0387-Option-for-maximum-exp-value-when-merging-orbs.patch diff --git a/patches/server/0394-ExperienceOrbMergeEvent.patch b/patches/server/0388-ExperienceOrbMergeEvent.patch similarity index 100% rename from patches/server/0394-ExperienceOrbMergeEvent.patch rename to patches/server/0388-ExperienceOrbMergeEvent.patch diff --git a/patches/server/0395-Fix-PotionEffect-ignores-icon-flag.patch b/patches/server/0389-Fix-PotionEffect-ignores-icon-flag.patch similarity index 100% rename from patches/server/0395-Fix-PotionEffect-ignores-icon-flag.patch rename to patches/server/0389-Fix-PotionEffect-ignores-icon-flag.patch diff --git a/patches/server/0396-Optimize-brigadier-child-sorting-performance.patch b/patches/server/0390-Optimize-brigadier-child-sorting-performance.patch similarity index 100% rename from patches/server/0396-Optimize-brigadier-child-sorting-performance.patch rename to patches/server/0390-Optimize-brigadier-child-sorting-performance.patch diff --git a/patches/server/0397-Potential-bed-API.patch b/patches/server/0391-Potential-bed-API.patch similarity index 100% rename from patches/server/0397-Potential-bed-API.patch rename to patches/server/0391-Potential-bed-API.patch diff --git a/patches/server/0398-Wait-for-Async-Tasks-during-shutdown.patch b/patches/server/0392-Wait-for-Async-Tasks-during-shutdown.patch similarity index 100% rename from patches/server/0398-Wait-for-Async-Tasks-during-shutdown.patch rename to patches/server/0392-Wait-for-Async-Tasks-during-shutdown.patch diff --git a/patches/server/0399-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch b/patches/server/0393-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch similarity index 100% rename from patches/server/0399-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch rename to patches/server/0393-Ensure-EntityRaider-respects-game-and-entity-rules-f.patch diff --git a/patches/server/0400-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/0394-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch similarity index 100% rename from patches/server/0400-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch rename to patches/server/0394-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch diff --git a/patches/server/0401-Reduce-allocation-of-Vec3D-by-entity-tracker.patch b/patches/server/0395-Reduce-allocation-of-Vec3D-by-entity-tracker.patch similarity index 100% rename from patches/server/0401-Reduce-allocation-of-Vec3D-by-entity-tracker.patch rename to patches/server/0395-Reduce-allocation-of-Vec3D-by-entity-tracker.patch diff --git a/patches/server/0402-Ensure-safe-gateway-teleport.patch b/patches/server/0396-Ensure-safe-gateway-teleport.patch similarity index 100% rename from patches/server/0402-Ensure-safe-gateway-teleport.patch rename to patches/server/0396-Ensure-safe-gateway-teleport.patch diff --git a/patches/server/0403-Add-option-for-console-having-all-permissions.patch b/patches/server/0397-Add-option-for-console-having-all-permissions.patch similarity index 100% rename from patches/server/0403-Add-option-for-console-having-all-permissions.patch rename to patches/server/0397-Add-option-for-console-having-all-permissions.patch diff --git a/patches/server/0404-Fix-villager-trading-demand-MC-163962.patch b/patches/server/0398-Fix-villager-trading-demand-MC-163962.patch similarity index 100% rename from patches/server/0404-Fix-villager-trading-demand-MC-163962.patch rename to patches/server/0398-Fix-villager-trading-demand-MC-163962.patch diff --git a/patches/server/0405-Maps-shouldn-t-load-chunks.patch b/patches/server/0399-Maps-shouldn-t-load-chunks.patch similarity index 100% rename from patches/server/0405-Maps-shouldn-t-load-chunks.patch rename to patches/server/0399-Maps-shouldn-t-load-chunks.patch diff --git a/patches/server/0406-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch b/patches/server/0400-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch similarity index 100% rename from patches/server/0406-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch rename to patches/server/0400-Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch diff --git a/patches/server/0407-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch b/patches/server/0401-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch similarity index 100% rename from patches/server/0407-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch rename to patches/server/0401-Fix-CraftScheduler-runTaskTimerAsynchronously-Plugin.patch diff --git a/patches/server/0408-Fix-piston-physics-inconsistency-MC-188840.patch b/patches/server/0402-Fix-piston-physics-inconsistency-MC-188840.patch similarity index 100% rename from patches/server/0408-Fix-piston-physics-inconsistency-MC-188840.patch rename to patches/server/0402-Fix-piston-physics-inconsistency-MC-188840.patch diff --git a/patches/server/0409-Fix-sand-duping.patch b/patches/server/0403-Fix-sand-duping.patch similarity index 100% rename from patches/server/0409-Fix-sand-duping.patch rename to patches/server/0403-Fix-sand-duping.patch diff --git a/patches/server/0410-Fix-missing-chunks-due-to-integer-overflow.patch b/patches/server/0404-Fix-missing-chunks-due-to-integer-overflow.patch similarity index 100% rename from patches/server/0410-Fix-missing-chunks-due-to-integer-overflow.patch rename to patches/server/0404-Fix-missing-chunks-due-to-integer-overflow.patch diff --git a/patches/server/0411-Prevent-position-desync-in-playerconnection-causing-.patch b/patches/server/0405-Prevent-position-desync-in-playerconnection-causing-.patch similarity index 100% rename from patches/server/0411-Prevent-position-desync-in-playerconnection-causing-.patch rename to patches/server/0405-Prevent-position-desync-in-playerconnection-causing-.patch diff --git a/patches/server/0412-Inventory-getHolder-method-without-block-snapshot.patch b/patches/server/0406-Inventory-getHolder-method-without-block-snapshot.patch similarity index 100% rename from patches/server/0412-Inventory-getHolder-method-without-block-snapshot.patch rename to patches/server/0406-Inventory-getHolder-method-without-block-snapshot.patch diff --git a/patches/server/0413-Improve-Arrow-API.patch b/patches/server/0407-Improve-Arrow-API.patch similarity index 100% rename from patches/server/0413-Improve-Arrow-API.patch rename to patches/server/0407-Improve-Arrow-API.patch diff --git a/patches/server/0414-Add-and-implement-PlayerRecipeBookClickEvent.patch b/patches/server/0408-Add-and-implement-PlayerRecipeBookClickEvent.patch similarity index 100% rename from patches/server/0414-Add-and-implement-PlayerRecipeBookClickEvent.patch rename to patches/server/0408-Add-and-implement-PlayerRecipeBookClickEvent.patch diff --git a/patches/server/0415-Hide-sync-chunk-writes-behind-flag.patch b/patches/server/0409-Hide-sync-chunk-writes-behind-flag.patch similarity index 100% rename from patches/server/0415-Hide-sync-chunk-writes-behind-flag.patch rename to patches/server/0409-Hide-sync-chunk-writes-behind-flag.patch diff --git a/patches/server/0416-Add-permission-for-command-blocks.patch b/patches/server/0410-Add-permission-for-command-blocks.patch similarity index 100% rename from patches/server/0416-Add-permission-for-command-blocks.patch rename to patches/server/0410-Add-permission-for-command-blocks.patch diff --git a/patches/server/0417-Ensure-Entity-AABB-s-are-never-invalid.patch b/patches/server/0411-Ensure-Entity-AABB-s-are-never-invalid.patch similarity index 100% rename from patches/server/0417-Ensure-Entity-AABB-s-are-never-invalid.patch rename to patches/server/0411-Ensure-Entity-AABB-s-are-never-invalid.patch diff --git a/patches/server/0418-Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/0412-Fix-Per-World-Difficulty-Remembering-Difficulty.patch similarity index 100% rename from patches/server/0418-Fix-Per-World-Difficulty-Remembering-Difficulty.patch rename to patches/server/0412-Fix-Per-World-Difficulty-Remembering-Difficulty.patch diff --git a/patches/server/0419-Paper-dumpitem-command.patch b/patches/server/0413-Paper-dumpitem-command.patch similarity index 100% rename from patches/server/0419-Paper-dumpitem-command.patch rename to patches/server/0413-Paper-dumpitem-command.patch diff --git a/patches/server/0420-Improve-Legacy-Component-serialization-size.patch b/patches/server/0414-Improve-Legacy-Component-serialization-size.patch similarity index 100% rename from patches/server/0420-Improve-Legacy-Component-serialization-size.patch rename to patches/server/0414-Improve-Legacy-Component-serialization-size.patch diff --git a/patches/server/0421-Optimize-Bit-Operations-by-inlining.patch b/patches/server/0415-Optimize-Bit-Operations-by-inlining.patch similarity index 100% rename from patches/server/0421-Optimize-Bit-Operations-by-inlining.patch rename to patches/server/0415-Optimize-Bit-Operations-by-inlining.patch diff --git a/patches/server/0422-Add-Plugin-Tickets-to-API-Chunk-Methods.patch b/patches/server/0416-Add-Plugin-Tickets-to-API-Chunk-Methods.patch similarity index 100% rename from patches/server/0422-Add-Plugin-Tickets-to-API-Chunk-Methods.patch rename to patches/server/0416-Add-Plugin-Tickets-to-API-Chunk-Methods.patch diff --git a/patches/server/0423-incremental-chunk-and-player-saving.patch b/patches/server/0417-incremental-chunk-and-player-saving.patch similarity index 100% rename from patches/server/0423-incremental-chunk-and-player-saving.patch rename to patches/server/0417-incremental-chunk-and-player-saving.patch diff --git a/patches/server/0424-Support-old-UUID-format-for-NBT.patch b/patches/server/0418-Support-old-UUID-format-for-NBT.patch similarity index 100% rename from patches/server/0424-Support-old-UUID-format-for-NBT.patch rename to patches/server/0418-Support-old-UUID-format-for-NBT.patch diff --git a/patches/server/0425-Clean-up-duplicated-GameProfile-Properties.patch b/patches/server/0419-Clean-up-duplicated-GameProfile-Properties.patch similarity index 100% rename from patches/server/0425-Clean-up-duplicated-GameProfile-Properties.patch rename to patches/server/0419-Clean-up-duplicated-GameProfile-Properties.patch diff --git a/patches/server/0426-Convert-legacy-attributes-in-Item-Meta.patch b/patches/server/0420-Convert-legacy-attributes-in-Item-Meta.patch similarity index 100% rename from patches/server/0426-Convert-legacy-attributes-in-Item-Meta.patch rename to patches/server/0420-Convert-legacy-attributes-in-Item-Meta.patch diff --git a/patches/server/0427-Remove-some-streams-from-structures.patch b/patches/server/0421-Remove-some-streams-from-structures.patch similarity index 100% rename from patches/server/0427-Remove-some-streams-from-structures.patch rename to patches/server/0421-Remove-some-streams-from-structures.patch diff --git a/patches/server/0428-Remove-streams-from-classes-related-villager-gossip.patch b/patches/server/0422-Remove-streams-from-classes-related-villager-gossip.patch similarity index 100% rename from patches/server/0428-Remove-streams-from-classes-related-villager-gossip.patch rename to patches/server/0422-Remove-streams-from-classes-related-villager-gossip.patch diff --git a/patches/server/0429-Support-components-in-ItemMeta.patch b/patches/server/0423-Support-components-in-ItemMeta.patch similarity index 100% rename from patches/server/0429-Support-components-in-ItemMeta.patch rename to patches/server/0423-Support-components-in-ItemMeta.patch diff --git a/patches/server/0430-Improve-fix-EntityTargetLivingEntityEvent.patch b/patches/server/0424-Improve-fix-EntityTargetLivingEntityEvent.patch similarity index 100% rename from patches/server/0430-Improve-fix-EntityTargetLivingEntityEvent.patch rename to patches/server/0424-Improve-fix-EntityTargetLivingEntityEvent.patch diff --git a/patches/server/0431-Add-entity-liquid-API.patch b/patches/server/0425-Add-entity-liquid-API.patch similarity index 100% rename from patches/server/0431-Add-entity-liquid-API.patch rename to patches/server/0425-Add-entity-liquid-API.patch diff --git a/patches/server/0432-Update-itemstack-legacy-name-and-lore.patch b/patches/server/0426-Update-itemstack-legacy-name-and-lore.patch similarity index 100% rename from patches/server/0432-Update-itemstack-legacy-name-and-lore.patch rename to patches/server/0426-Update-itemstack-legacy-name-and-lore.patch diff --git a/patches/server/0433-Spawn-player-in-correct-world-on-login.patch b/patches/server/0427-Spawn-player-in-correct-world-on-login.patch similarity index 100% rename from patches/server/0433-Spawn-player-in-correct-world-on-login.patch rename to patches/server/0427-Spawn-player-in-correct-world-on-login.patch diff --git a/patches/server/0434-Add-PrepareResultEvent.patch b/patches/server/0428-Add-PrepareResultEvent.patch similarity index 100% rename from patches/server/0434-Add-PrepareResultEvent.patch rename to patches/server/0428-Add-PrepareResultEvent.patch diff --git a/patches/server/0435-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch b/patches/server/0429-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch similarity index 100% rename from patches/server/0435-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch rename to patches/server/0429-Don-t-check-chunk-for-portal-on-world-gen-entity-add.patch diff --git a/patches/server/0436-Optimize-NetworkManager-Exception-Handling.patch b/patches/server/0430-Optimize-NetworkManager-Exception-Handling.patch similarity index 100% rename from patches/server/0436-Optimize-NetworkManager-Exception-Handling.patch rename to patches/server/0430-Optimize-NetworkManager-Exception-Handling.patch diff --git a/patches/server/0437-Fix-arrows-never-despawning-MC-125757.patch b/patches/server/0431-Fix-arrows-never-despawning-MC-125757.patch similarity index 100% rename from patches/server/0437-Fix-arrows-never-despawning-MC-125757.patch rename to patches/server/0431-Fix-arrows-never-despawning-MC-125757.patch diff --git a/patches/server/0438-Thread-Safe-Vanilla-Command-permission-checking.patch b/patches/server/0432-Thread-Safe-Vanilla-Command-permission-checking.patch similarity index 100% rename from patches/server/0438-Thread-Safe-Vanilla-Command-permission-checking.patch rename to patches/server/0432-Thread-Safe-Vanilla-Command-permission-checking.patch diff --git a/patches/server/0439-Fix-SPIGOT-5989.patch b/patches/server/0433-Fix-SPIGOT-5989.patch similarity index 100% rename from patches/server/0439-Fix-SPIGOT-5989.patch rename to patches/server/0433-Fix-SPIGOT-5989.patch diff --git a/patches/server/0440-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch b/patches/server/0434-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch similarity index 100% rename from patches/server/0440-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch rename to patches/server/0434-Fix-SPIGOT-5824-Bukkit-world-container-is-not-used.patch diff --git a/patches/server/0441-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch b/patches/server/0435-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch similarity index 100% rename from patches/server/0441-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch rename to patches/server/0435-Fix-SPIGOT-5885-Unable-to-disable-advancements.patch diff --git a/patches/server/0442-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch b/patches/server/0436-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch similarity index 100% rename from patches/server/0442-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch rename to patches/server/0436-Fix-AdvancementDataPlayer-leak-due-from-quitting-ear.patch diff --git a/patches/server/0443-Fix-some-rails-connecting-improperly.patch b/patches/server/0437-Fix-some-rails-connecting-improperly.patch similarity index 100% rename from patches/server/0443-Fix-some-rails-connecting-improperly.patch rename to patches/server/0437-Fix-some-rails-connecting-improperly.patch diff --git a/patches/server/0444-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch b/patches/server/0438-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch similarity index 100% rename from patches/server/0444-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch rename to patches/server/0438-Fix-regex-mistake-in-CB-NBT-int-deserialization.patch diff --git a/patches/server/0445-Do-not-let-the-server-load-chunks-from-newer-version.patch b/patches/server/0439-Do-not-let-the-server-load-chunks-from-newer-version.patch similarity index 100% rename from patches/server/0445-Do-not-let-the-server-load-chunks-from-newer-version.patch rename to patches/server/0439-Do-not-let-the-server-load-chunks-from-newer-version.patch diff --git a/patches/server/0446-Brand-support.patch b/patches/server/0440-Brand-support.patch similarity index 100% rename from patches/server/0446-Brand-support.patch rename to patches/server/0440-Brand-support.patch diff --git a/patches/server/0447-Add-setMaxPlayers-API.patch b/patches/server/0441-Add-setMaxPlayers-API.patch similarity index 100% rename from patches/server/0447-Add-setMaxPlayers-API.patch rename to patches/server/0441-Add-setMaxPlayers-API.patch diff --git a/patches/server/0448-Add-playPickupItemAnimation-to-LivingEntity.patch b/patches/server/0442-Add-playPickupItemAnimation-to-LivingEntity.patch similarity index 100% rename from patches/server/0448-Add-playPickupItemAnimation-to-LivingEntity.patch rename to patches/server/0442-Add-playPickupItemAnimation-to-LivingEntity.patch diff --git a/patches/server/0449-Don-t-require-FACING-data.patch b/patches/server/0443-Don-t-require-FACING-data.patch similarity index 100% rename from patches/server/0449-Don-t-require-FACING-data.patch rename to patches/server/0443-Don-t-require-FACING-data.patch diff --git a/patches/server/0450-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch b/patches/server/0444-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch similarity index 100% rename from patches/server/0450-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch rename to patches/server/0444-Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch diff --git a/patches/server/0451-Add-moon-phase-API.patch b/patches/server/0445-Add-moon-phase-API.patch similarity index 100% rename from patches/server/0451-Add-moon-phase-API.patch rename to patches/server/0445-Add-moon-phase-API.patch diff --git a/patches/server/0452-Prevent-headless-pistons-from-being-created.patch b/patches/server/0446-Prevent-headless-pistons-from-being-created.patch similarity index 100% rename from patches/server/0452-Prevent-headless-pistons-from-being-created.patch rename to patches/server/0446-Prevent-headless-pistons-from-being-created.patch diff --git a/patches/server/0453-Add-BellRingEvent.patch b/patches/server/0447-Add-BellRingEvent.patch similarity index 100% rename from patches/server/0453-Add-BellRingEvent.patch rename to patches/server/0447-Add-BellRingEvent.patch diff --git a/patches/server/0454-Add-zombie-targets-turtle-egg-config.patch b/patches/server/0448-Add-zombie-targets-turtle-egg-config.patch similarity index 100% rename from patches/server/0454-Add-zombie-targets-turtle-egg-config.patch rename to patches/server/0448-Add-zombie-targets-turtle-egg-config.patch diff --git a/patches/server/0455-Buffer-joins-to-world.patch b/patches/server/0449-Buffer-joins-to-world.patch similarity index 100% rename from patches/server/0455-Buffer-joins-to-world.patch rename to patches/server/0449-Buffer-joins-to-world.patch diff --git a/patches/server/0456-Eigencraft-redstone-implementation.patch b/patches/server/0450-Eigencraft-redstone-implementation.patch similarity index 100% rename from patches/server/0456-Eigencraft-redstone-implementation.patch rename to patches/server/0450-Eigencraft-redstone-implementation.patch diff --git a/patches/server/0457-Fix-hex-colors-not-working-in-some-kick-messages.patch b/patches/server/0451-Fix-hex-colors-not-working-in-some-kick-messages.patch similarity index 100% rename from patches/server/0457-Fix-hex-colors-not-working-in-some-kick-messages.patch rename to patches/server/0451-Fix-hex-colors-not-working-in-some-kick-messages.patch diff --git a/patches/server/0458-PortalCreateEvent-needs-to-know-its-entity.patch b/patches/server/0452-PortalCreateEvent-needs-to-know-its-entity.patch similarity index 100% rename from patches/server/0458-PortalCreateEvent-needs-to-know-its-entity.patch rename to patches/server/0452-PortalCreateEvent-needs-to-know-its-entity.patch diff --git a/patches/server/0459-Fix-CraftTeam-null-check.patch b/patches/server/0453-Fix-CraftTeam-null-check.patch similarity index 100% rename from patches/server/0459-Fix-CraftTeam-null-check.patch rename to patches/server/0453-Fix-CraftTeam-null-check.patch diff --git a/patches/server/0460-Add-more-Evoker-API.patch b/patches/server/0454-Add-more-Evoker-API.patch similarity index 100% rename from patches/server/0460-Add-more-Evoker-API.patch rename to patches/server/0454-Add-more-Evoker-API.patch diff --git a/patches/server/0461-Add-methods-to-get-translation-keys.patch b/patches/server/0455-Add-methods-to-get-translation-keys.patch similarity index 100% rename from patches/server/0461-Add-methods-to-get-translation-keys.patch rename to patches/server/0455-Add-methods-to-get-translation-keys.patch diff --git a/patches/server/0462-Create-HoverEvent-from-ItemStack-Entity.patch b/patches/server/0456-Create-HoverEvent-from-ItemStack-Entity.patch similarity index 100% rename from patches/server/0462-Create-HoverEvent-from-ItemStack-Entity.patch rename to patches/server/0456-Create-HoverEvent-from-ItemStack-Entity.patch diff --git a/patches/server/0463-Cache-block-data-strings.patch b/patches/server/0457-Cache-block-data-strings.patch similarity index 100% rename from patches/server/0463-Cache-block-data-strings.patch rename to patches/server/0457-Cache-block-data-strings.patch diff --git a/patches/server/0464-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch b/patches/server/0458-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch similarity index 100% rename from patches/server/0464-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch rename to patches/server/0458-Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch diff --git a/patches/server/0465-Add-additional-open-container-api-to-HumanEntity.patch b/patches/server/0459-Add-additional-open-container-api-to-HumanEntity.patch similarity index 100% rename from patches/server/0465-Add-additional-open-container-api-to-HumanEntity.patch rename to patches/server/0459-Add-additional-open-container-api-to-HumanEntity.patch diff --git a/patches/server/0466-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch b/patches/server/0460-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch similarity index 100% rename from patches/server/0466-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch rename to patches/server/0460-Cache-DataFixerUpper-Rewrite-Rules-on-demand.patch diff --git a/patches/server/0467-Extend-block-drop-capture-to-capture-all-items-added.patch b/patches/server/0461-Extend-block-drop-capture-to-capture-all-items-added.patch similarity index 100% rename from patches/server/0467-Extend-block-drop-capture-to-capture-all-items-added.patch rename to patches/server/0461-Extend-block-drop-capture-to-capture-all-items-added.patch diff --git a/patches/server/0468-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch b/patches/server/0462-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch similarity index 100% rename from patches/server/0468-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch rename to patches/server/0462-Expose-the-Entity-Counter-to-allow-plugins-to-use-va.patch diff --git a/patches/server/0469-Lazily-track-plugin-scoreboards-by-default.patch b/patches/server/0463-Lazily-track-plugin-scoreboards-by-default.patch similarity index 100% rename from patches/server/0469-Lazily-track-plugin-scoreboards-by-default.patch rename to patches/server/0463-Lazily-track-plugin-scoreboards-by-default.patch diff --git a/patches/server/0470-Entity-isTicking.patch b/patches/server/0464-Entity-isTicking.patch similarity index 100% rename from patches/server/0470-Entity-isTicking.patch rename to patches/server/0464-Entity-isTicking.patch diff --git a/patches/server/0471-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch b/patches/server/0465-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch similarity index 100% rename from patches/server/0471-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch rename to patches/server/0465-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch diff --git a/patches/server/0472-Fix-Concurrency-issue-in-ShufflingList.patch b/patches/server/0466-Fix-Concurrency-issue-in-ShufflingList.patch similarity index 100% rename from patches/server/0472-Fix-Concurrency-issue-in-ShufflingList.patch rename to patches/server/0466-Fix-Concurrency-issue-in-ShufflingList.patch diff --git a/patches/server/0473-Reset-Ender-Crystals-on-Dragon-Spawn.patch b/patches/server/0467-Reset-Ender-Crystals-on-Dragon-Spawn.patch similarity index 100% rename from patches/server/0473-Reset-Ender-Crystals-on-Dragon-Spawn.patch rename to patches/server/0467-Reset-Ender-Crystals-on-Dragon-Spawn.patch diff --git a/patches/server/0474-Fix-for-large-move-vectors-crashing-server.patch b/patches/server/0468-Fix-for-large-move-vectors-crashing-server.patch similarity index 100% rename from patches/server/0474-Fix-for-large-move-vectors-crashing-server.patch rename to patches/server/0468-Fix-for-large-move-vectors-crashing-server.patch diff --git a/patches/server/0475-Optimise-getType-calls.patch b/patches/server/0469-Optimise-getType-calls.patch similarity index 100% rename from patches/server/0475-Optimise-getType-calls.patch rename to patches/server/0469-Optimise-getType-calls.patch diff --git a/patches/server/0476-Villager-resetOffers.patch b/patches/server/0470-Villager-resetOffers.patch similarity index 100% rename from patches/server/0476-Villager-resetOffers.patch rename to patches/server/0470-Villager-resetOffers.patch diff --git a/patches/server/0477-Retain-block-place-order-when-capturing-blockstates.patch b/patches/server/0471-Retain-block-place-order-when-capturing-blockstates.patch similarity index 100% rename from patches/server/0477-Retain-block-place-order-when-capturing-blockstates.patch rename to patches/server/0471-Retain-block-place-order-when-capturing-blockstates.patch diff --git a/patches/server/0478-Reduce-blockpos-allocation-from-pathfinding.patch b/patches/server/0472-Reduce-blockpos-allocation-from-pathfinding.patch similarity index 100% rename from patches/server/0478-Reduce-blockpos-allocation-from-pathfinding.patch rename to patches/server/0472-Reduce-blockpos-allocation-from-pathfinding.patch diff --git a/patches/server/0479-Fix-item-locations-dropped-from-campfires.patch b/patches/server/0473-Fix-item-locations-dropped-from-campfires.patch similarity index 100% rename from patches/server/0479-Fix-item-locations-dropped-from-campfires.patch rename to patches/server/0473-Fix-item-locations-dropped-from-campfires.patch diff --git a/patches/server/0480-Player-elytra-boost-API.patch b/patches/server/0474-Player-elytra-boost-API.patch similarity index 100% rename from patches/server/0480-Player-elytra-boost-API.patch rename to patches/server/0474-Player-elytra-boost-API.patch diff --git a/patches/server/0481-Fixed-TileEntityBell-memory-leak.patch b/patches/server/0475-Fixed-TileEntityBell-memory-leak.patch similarity index 100% rename from patches/server/0481-Fixed-TileEntityBell-memory-leak.patch rename to patches/server/0475-Fixed-TileEntityBell-memory-leak.patch diff --git a/patches/server/0482-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch b/patches/server/0476-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch similarity index 100% rename from patches/server/0482-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch rename to patches/server/0476-Avoid-error-bubbling-up-when-item-stack-is-empty-in-.patch diff --git a/patches/server/0483-Add-getOfflinePlayerIfCached-String.patch b/patches/server/0477-Add-getOfflinePlayerIfCached-String.patch similarity index 100% rename from patches/server/0483-Add-getOfflinePlayerIfCached-String.patch rename to patches/server/0477-Add-getOfflinePlayerIfCached-String.patch diff --git a/patches/server/0484-Add-ignore-discounts-API.patch b/patches/server/0478-Add-ignore-discounts-API.patch similarity index 100% rename from patches/server/0484-Add-ignore-discounts-API.patch rename to patches/server/0478-Add-ignore-discounts-API.patch diff --git a/patches/server/0485-Toggle-for-removing-existing-dragon.patch b/patches/server/0479-Toggle-for-removing-existing-dragon.patch similarity index 100% rename from patches/server/0485-Toggle-for-removing-existing-dragon.patch rename to patches/server/0479-Toggle-for-removing-existing-dragon.patch diff --git a/patches/server/0486-Fix-client-lag-on-advancement-loading.patch b/patches/server/0480-Fix-client-lag-on-advancement-loading.patch similarity index 100% rename from patches/server/0486-Fix-client-lag-on-advancement-loading.patch rename to patches/server/0480-Fix-client-lag-on-advancement-loading.patch diff --git a/patches/server/0487-Item-no-age-no-player-pickup.patch b/patches/server/0481-Item-no-age-no-player-pickup.patch similarity index 100% rename from patches/server/0487-Item-no-age-no-player-pickup.patch rename to patches/server/0481-Item-no-age-no-player-pickup.patch diff --git a/patches/server/0488-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch b/patches/server/0482-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch similarity index 100% rename from patches/server/0488-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch rename to patches/server/0482-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch diff --git a/patches/server/0489-Beacon-API-custom-effect-ranges.patch b/patches/server/0483-Beacon-API-custom-effect-ranges.patch similarity index 100% rename from patches/server/0489-Beacon-API-custom-effect-ranges.patch rename to patches/server/0483-Beacon-API-custom-effect-ranges.patch diff --git a/patches/server/0490-Add-API-for-quit-reason.patch b/patches/server/0484-Add-API-for-quit-reason.patch similarity index 100% rename from patches/server/0490-Add-API-for-quit-reason.patch rename to patches/server/0484-Add-API-for-quit-reason.patch diff --git a/patches/server/0491-Add-Wandering-Trader-spawn-rate-config-options.patch b/patches/server/0485-Add-Wandering-Trader-spawn-rate-config-options.patch similarity index 100% rename from patches/server/0491-Add-Wandering-Trader-spawn-rate-config-options.patch rename to patches/server/0485-Add-Wandering-Trader-spawn-rate-config-options.patch diff --git a/patches/server/0492-Expose-world-spawn-angle.patch b/patches/server/0486-Expose-world-spawn-angle.patch similarity index 100% rename from patches/server/0492-Expose-world-spawn-angle.patch rename to patches/server/0486-Expose-world-spawn-angle.patch diff --git a/patches/server/0493-Add-Destroy-Speed-API.patch b/patches/server/0487-Add-Destroy-Speed-API.patch similarity index 100% rename from patches/server/0493-Add-Destroy-Speed-API.patch rename to patches/server/0487-Add-Destroy-Speed-API.patch diff --git a/patches/server/0494-Fix-Player-spawnParticle-x-y-z-precision-loss.patch b/patches/server/0488-Fix-Player-spawnParticle-x-y-z-precision-loss.patch similarity index 100% rename from patches/server/0494-Fix-Player-spawnParticle-x-y-z-precision-loss.patch rename to patches/server/0488-Fix-Player-spawnParticle-x-y-z-precision-loss.patch diff --git a/patches/server/0495-Add-LivingEntity-clearActiveItem.patch b/patches/server/0489-Add-LivingEntity-clearActiveItem.patch similarity index 100% rename from patches/server/0495-Add-LivingEntity-clearActiveItem.patch rename to patches/server/0489-Add-LivingEntity-clearActiveItem.patch diff --git a/patches/server/0496-Add-PlayerItemCooldownEvent.patch b/patches/server/0490-Add-PlayerItemCooldownEvent.patch similarity index 100% rename from patches/server/0496-Add-PlayerItemCooldownEvent.patch rename to patches/server/0490-Add-PlayerItemCooldownEvent.patch diff --git a/patches/server/0497-Significantly-improve-performance-of-the-end-generat.patch b/patches/server/0491-Significantly-improve-performance-of-the-end-generat.patch similarity index 100% rename from patches/server/0497-Significantly-improve-performance-of-the-end-generat.patch rename to patches/server/0491-Significantly-improve-performance-of-the-end-generat.patch diff --git a/patches/server/0498-More-lightning-API.patch b/patches/server/0492-More-lightning-API.patch similarity index 100% rename from patches/server/0498-More-lightning-API.patch rename to patches/server/0492-More-lightning-API.patch diff --git a/patches/server/0499-Climbing-should-not-bypass-cramming-gamerule.patch b/patches/server/0493-Climbing-should-not-bypass-cramming-gamerule.patch similarity index 100% rename from patches/server/0499-Climbing-should-not-bypass-cramming-gamerule.patch rename to patches/server/0493-Climbing-should-not-bypass-cramming-gamerule.patch diff --git a/patches/server/0500-Added-missing-default-perms-for-commands.patch b/patches/server/0494-Added-missing-default-perms-for-commands.patch similarity index 100% rename from patches/server/0500-Added-missing-default-perms-for-commands.patch rename to patches/server/0494-Added-missing-default-perms-for-commands.patch diff --git a/patches/server/0501-Add-PlayerShearBlockEvent.patch b/patches/server/0495-Add-PlayerShearBlockEvent.patch similarity index 100% rename from patches/server/0501-Add-PlayerShearBlockEvent.patch rename to patches/server/0495-Add-PlayerShearBlockEvent.patch diff --git a/patches/server/0502-Fix-curing-zombie-villager-discount-exploit.patch b/patches/server/0496-Fix-curing-zombie-villager-discount-exploit.patch similarity index 100% rename from patches/server/0502-Fix-curing-zombie-villager-discount-exploit.patch rename to patches/server/0496-Fix-curing-zombie-villager-discount-exploit.patch diff --git a/patches/server/0503-Limit-recipe-packets.patch b/patches/server/0497-Limit-recipe-packets.patch similarity index 100% rename from patches/server/0503-Limit-recipe-packets.patch rename to patches/server/0497-Limit-recipe-packets.patch diff --git a/patches/server/0504-Fix-CraftSound-backwards-compatibility.patch b/patches/server/0498-Fix-CraftSound-backwards-compatibility.patch similarity index 100% rename from patches/server/0504-Fix-CraftSound-backwards-compatibility.patch rename to patches/server/0498-Fix-CraftSound-backwards-compatibility.patch diff --git a/patches/server/0505-Player-Chunk-Load-Unload-Events.patch b/patches/server/0499-Player-Chunk-Load-Unload-Events.patch similarity index 100% rename from patches/server/0505-Player-Chunk-Load-Unload-Events.patch rename to patches/server/0499-Player-Chunk-Load-Unload-Events.patch diff --git a/patches/server/0506-Optimize-Dynamic-get-Missing-Keys.patch b/patches/server/0500-Optimize-Dynamic-get-Missing-Keys.patch similarity index 100% rename from patches/server/0506-Optimize-Dynamic-get-Missing-Keys.patch rename to patches/server/0500-Optimize-Dynamic-get-Missing-Keys.patch diff --git a/patches/server/0507-Expose-LivingEntity-hurt-direction.patch b/patches/server/0501-Expose-LivingEntity-hurt-direction.patch similarity index 100% rename from patches/server/0507-Expose-LivingEntity-hurt-direction.patch rename to patches/server/0501-Expose-LivingEntity-hurt-direction.patch diff --git a/patches/server/0508-Add-OBSTRUCTED-reason-to-BedEnterResult.patch b/patches/server/0502-Add-OBSTRUCTED-reason-to-BedEnterResult.patch similarity index 100% rename from patches/server/0508-Add-OBSTRUCTED-reason-to-BedEnterResult.patch rename to patches/server/0502-Add-OBSTRUCTED-reason-to-BedEnterResult.patch diff --git a/patches/server/0509-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch b/patches/server/0503-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch similarity index 100% rename from patches/server/0509-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch rename to patches/server/0503-Do-not-crash-from-invalid-ingredient-lists-in-Villag.patch diff --git a/patches/server/0510-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch b/patches/server/0504-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch similarity index 100% rename from patches/server/0510-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch rename to patches/server/0504-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch diff --git a/patches/server/0511-Implement-TargetHitEvent.patch b/patches/server/0505-Implement-TargetHitEvent.patch similarity index 100% rename from patches/server/0511-Implement-TargetHitEvent.patch rename to patches/server/0505-Implement-TargetHitEvent.patch diff --git a/patches/server/0512-MC-4-Fix-item-position-desync.patch b/patches/server/0506-MC-4-Fix-item-position-desync.patch similarity index 100% rename from patches/server/0512-MC-4-Fix-item-position-desync.patch rename to patches/server/0506-MC-4-Fix-item-position-desync.patch diff --git a/patches/server/0513-Additional-Block-Material-API-s.patch b/patches/server/0507-Additional-Block-Material-API-s.patch similarity index 100% rename from patches/server/0513-Additional-Block-Material-API-s.patch rename to patches/server/0507-Additional-Block-Material-API-s.patch diff --git a/patches/server/0514-Fix-harming-potion-dupe.patch b/patches/server/0508-Fix-harming-potion-dupe.patch similarity index 100% rename from patches/server/0514-Fix-harming-potion-dupe.patch rename to patches/server/0508-Fix-harming-potion-dupe.patch diff --git a/patches/server/0515-Implement-API-to-get-Material-from-Boats-and-Minecar.patch b/patches/server/0509-Implement-API-to-get-Material-from-Boats-and-Minecar.patch similarity index 100% rename from patches/server/0515-Implement-API-to-get-Material-from-Boats-and-Minecar.patch rename to patches/server/0509-Implement-API-to-get-Material-from-Boats-and-Minecar.patch diff --git a/patches/server/0516-Cache-burn-durations.patch b/patches/server/0510-Cache-burn-durations.patch similarity index 100% rename from patches/server/0516-Cache-burn-durations.patch rename to patches/server/0510-Cache-burn-durations.patch diff --git a/patches/server/0517-Allow-disabling-mob-spawner-spawn-egg-transformation.patch b/patches/server/0511-Allow-disabling-mob-spawner-spawn-egg-transformation.patch similarity index 100% rename from patches/server/0517-Allow-disabling-mob-spawner-spawn-egg-transformation.patch rename to patches/server/0511-Allow-disabling-mob-spawner-spawn-egg-transformation.patch diff --git a/patches/server/0518-Fix-Not-a-string-Map-Conversion-spam.patch b/patches/server/0512-Fix-Not-a-string-Map-Conversion-spam.patch similarity index 100% rename from patches/server/0518-Fix-Not-a-string-Map-Conversion-spam.patch rename to patches/server/0512-Fix-Not-a-string-Map-Conversion-spam.patch diff --git a/patches/server/0519-Implement-PlayerFlowerPotManipulateEvent.patch b/patches/server/0513-Implement-PlayerFlowerPotManipulateEvent.patch similarity index 100% rename from patches/server/0519-Implement-PlayerFlowerPotManipulateEvent.patch rename to patches/server/0513-Implement-PlayerFlowerPotManipulateEvent.patch diff --git a/patches/server/0520-Fix-interact-event-not-being-called-in-adventure.patch b/patches/server/0514-Fix-interact-event-not-being-called-in-adventure.patch similarity index 100% rename from patches/server/0520-Fix-interact-event-not-being-called-in-adventure.patch rename to patches/server/0514-Fix-interact-event-not-being-called-in-adventure.patch diff --git a/patches/server/0521-Zombie-API-breaking-doors.patch b/patches/server/0515-Zombie-API-breaking-doors.patch similarity index 100% rename from patches/server/0521-Zombie-API-breaking-doors.patch rename to patches/server/0515-Zombie-API-breaking-doors.patch diff --git a/patches/server/0522-Fix-nerfed-slime-when-splitting.patch b/patches/server/0516-Fix-nerfed-slime-when-splitting.patch similarity index 100% rename from patches/server/0522-Fix-nerfed-slime-when-splitting.patch rename to patches/server/0516-Fix-nerfed-slime-when-splitting.patch diff --git a/patches/server/0523-Add-EntityLoadCrossbowEvent.patch b/patches/server/0517-Add-EntityLoadCrossbowEvent.patch similarity index 100% rename from patches/server/0523-Add-EntityLoadCrossbowEvent.patch rename to patches/server/0517-Add-EntityLoadCrossbowEvent.patch diff --git a/patches/server/0524-Added-WorldGameRuleChangeEvent.patch b/patches/server/0518-Added-WorldGameRuleChangeEvent.patch similarity index 100% rename from patches/server/0524-Added-WorldGameRuleChangeEvent.patch rename to patches/server/0518-Added-WorldGameRuleChangeEvent.patch diff --git a/patches/server/0525-Added-ServerResourcesReloadedEvent.patch b/patches/server/0519-Added-ServerResourcesReloadedEvent.patch similarity index 100% rename from patches/server/0525-Added-ServerResourcesReloadedEvent.patch rename to patches/server/0519-Added-ServerResourcesReloadedEvent.patch diff --git a/patches/server/0526-Added-world-settings-for-mobs-picking-up-loot.patch b/patches/server/0520-Added-world-settings-for-mobs-picking-up-loot.patch similarity index 100% rename from patches/server/0526-Added-world-settings-for-mobs-picking-up-loot.patch rename to patches/server/0520-Added-world-settings-for-mobs-picking-up-loot.patch diff --git a/patches/server/0527-Implemented-BlockFailedDispenseEvent.patch b/patches/server/0521-Implemented-BlockFailedDispenseEvent.patch similarity index 100% rename from patches/server/0527-Implemented-BlockFailedDispenseEvent.patch rename to patches/server/0521-Implemented-BlockFailedDispenseEvent.patch diff --git a/patches/server/0528-Added-PlayerLecternPageChangeEvent.patch b/patches/server/0522-Added-PlayerLecternPageChangeEvent.patch similarity index 100% rename from patches/server/0528-Added-PlayerLecternPageChangeEvent.patch rename to patches/server/0522-Added-PlayerLecternPageChangeEvent.patch diff --git a/patches/server/0529-Added-PlayerLoomPatternSelectEvent.patch b/patches/server/0523-Added-PlayerLoomPatternSelectEvent.patch similarity index 100% rename from patches/server/0529-Added-PlayerLoomPatternSelectEvent.patch rename to patches/server/0523-Added-PlayerLoomPatternSelectEvent.patch diff --git a/patches/server/0530-Configurable-door-breaking-difficulty.patch b/patches/server/0524-Configurable-door-breaking-difficulty.patch similarity index 100% rename from patches/server/0530-Configurable-door-breaking-difficulty.patch rename to patches/server/0524-Configurable-door-breaking-difficulty.patch diff --git a/patches/server/0531-Empty-commands-shall-not-be-dispatched.patch b/patches/server/0525-Empty-commands-shall-not-be-dispatched.patch similarity index 100% rename from patches/server/0531-Empty-commands-shall-not-be-dispatched.patch rename to patches/server/0525-Empty-commands-shall-not-be-dispatched.patch diff --git a/patches/server/0532-Implement-API-to-expose-exact-interaction-point.patch b/patches/server/0526-Implement-API-to-expose-exact-interaction-point.patch similarity index 100% rename from patches/server/0532-Implement-API-to-expose-exact-interaction-point.patch rename to patches/server/0526-Implement-API-to-expose-exact-interaction-point.patch diff --git a/patches/server/0533-Remove-stale-POIs.patch b/patches/server/0527-Remove-stale-POIs.patch similarity index 100% rename from patches/server/0533-Remove-stale-POIs.patch rename to patches/server/0527-Remove-stale-POIs.patch diff --git a/patches/server/0534-Fix-villager-boat-exploit.patch b/patches/server/0528-Fix-villager-boat-exploit.patch similarity index 100% rename from patches/server/0534-Fix-villager-boat-exploit.patch rename to patches/server/0528-Fix-villager-boat-exploit.patch diff --git a/patches/server/0535-Add-sendOpLevel-API.patch b/patches/server/0529-Add-sendOpLevel-API.patch similarity index 100% rename from patches/server/0535-Add-sendOpLevel-API.patch rename to patches/server/0529-Add-sendOpLevel-API.patch diff --git a/patches/server/0536-TODO-Registry-Modification-API.patch b/patches/server/0530-TODO-Registry-Modification-API.patch similarity index 100% rename from patches/server/0536-TODO-Registry-Modification-API.patch rename to patches/server/0530-TODO-Registry-Modification-API.patch diff --git a/patches/server/0537-Add-StructuresLocateEvent.patch b/patches/server/0531-Add-StructuresLocateEvent.patch similarity index 100% rename from patches/server/0537-Add-StructuresLocateEvent.patch rename to patches/server/0531-Add-StructuresLocateEvent.patch diff --git a/patches/server/0538-Collision-option-for-requiring-a-player-participant.patch b/patches/server/0532-Collision-option-for-requiring-a-player-participant.patch similarity index 100% rename from patches/server/0538-Collision-option-for-requiring-a-player-participant.patch rename to patches/server/0532-Collision-option-for-requiring-a-player-participant.patch diff --git a/patches/server/0539-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch b/patches/server/0533-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch similarity index 100% rename from patches/server/0539-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch rename to patches/server/0533-Remove-ProjectileHitEvent-call-when-fireballs-dead.patch diff --git a/patches/server/0540-Return-chat-component-with-empty-text-instead-of-thr.patch b/patches/server/0534-Return-chat-component-with-empty-text-instead-of-thr.patch similarity index 100% rename from patches/server/0540-Return-chat-component-with-empty-text-instead-of-thr.patch rename to patches/server/0534-Return-chat-component-with-empty-text-instead-of-thr.patch diff --git a/patches/server/0541-Make-schedule-command-per-world.patch b/patches/server/0535-Make-schedule-command-per-world.patch similarity index 100% rename from patches/server/0541-Make-schedule-command-per-world.patch rename to patches/server/0535-Make-schedule-command-per-world.patch diff --git a/patches/server/0542-Configurable-max-leash-distance.patch b/patches/server/0536-Configurable-max-leash-distance.patch similarity index 100% rename from patches/server/0542-Configurable-max-leash-distance.patch rename to patches/server/0536-Configurable-max-leash-distance.patch diff --git a/patches/server/0543-Implement-BlockPreDispenseEvent.patch b/patches/server/0537-Implement-BlockPreDispenseEvent.patch similarity index 100% rename from patches/server/0543-Implement-BlockPreDispenseEvent.patch rename to patches/server/0537-Implement-BlockPreDispenseEvent.patch diff --git a/patches/server/0544-Added-firing-of-PlayerChangeBeaconEffectEvent.patch b/patches/server/0538-Added-firing-of-PlayerChangeBeaconEffectEvent.patch similarity index 100% rename from patches/server/0544-Added-firing-of-PlayerChangeBeaconEffectEvent.patch rename to patches/server/0538-Added-firing-of-PlayerChangeBeaconEffectEvent.patch diff --git a/patches/server/0545-Add-toggle-for-always-placing-the-dragon-egg.patch b/patches/server/0539-Add-toggle-for-always-placing-the-dragon-egg.patch similarity index 100% rename from patches/server/0545-Add-toggle-for-always-placing-the-dragon-egg.patch rename to patches/server/0539-Add-toggle-for-always-placing-the-dragon-egg.patch diff --git a/patches/server/0546-Added-PlayerStonecutterRecipeSelectEvent.patch b/patches/server/0540-Added-PlayerStonecutterRecipeSelectEvent.patch similarity index 100% rename from patches/server/0546-Added-PlayerStonecutterRecipeSelectEvent.patch rename to patches/server/0540-Added-PlayerStonecutterRecipeSelectEvent.patch diff --git a/patches/server/0547-Add-dropLeash-variable-to-EntityUnleashEvent.patch b/patches/server/0541-Add-dropLeash-variable-to-EntityUnleashEvent.patch similarity index 100% rename from patches/server/0547-Add-dropLeash-variable-to-EntityUnleashEvent.patch rename to patches/server/0541-Add-dropLeash-variable-to-EntityUnleashEvent.patch diff --git a/patches/server/0548-Reset-shield-blocking-on-dimension-change.patch b/patches/server/0542-Reset-shield-blocking-on-dimension-change.patch similarity index 100% rename from patches/server/0548-Reset-shield-blocking-on-dimension-change.patch rename to patches/server/0542-Reset-shield-blocking-on-dimension-change.patch diff --git a/patches/server/0549-add-DragonEggFormEvent.patch b/patches/server/0543-add-DragonEggFormEvent.patch similarity index 100% rename from patches/server/0549-add-DragonEggFormEvent.patch rename to patches/server/0543-add-DragonEggFormEvent.patch diff --git a/patches/server/0550-EntityMoveEvent.patch b/patches/server/0544-EntityMoveEvent.patch similarity index 100% rename from patches/server/0550-EntityMoveEvent.patch rename to patches/server/0544-EntityMoveEvent.patch diff --git a/patches/server/0551-added-option-to-disable-pathfinding-updates-on-block.patch b/patches/server/0545-added-option-to-disable-pathfinding-updates-on-block.patch similarity index 100% rename from patches/server/0551-added-option-to-disable-pathfinding-updates-on-block.patch rename to patches/server/0545-added-option-to-disable-pathfinding-updates-on-block.patch diff --git a/patches/server/0552-Inline-shift-direction-fields.patch b/patches/server/0546-Inline-shift-direction-fields.patch similarity index 100% rename from patches/server/0552-Inline-shift-direction-fields.patch rename to patches/server/0546-Inline-shift-direction-fields.patch diff --git a/patches/server/0553-Allow-adding-items-to-BlockDropItemEvent.patch b/patches/server/0547-Allow-adding-items-to-BlockDropItemEvent.patch similarity index 100% rename from patches/server/0553-Allow-adding-items-to-BlockDropItemEvent.patch rename to patches/server/0547-Allow-adding-items-to-BlockDropItemEvent.patch diff --git a/patches/server/0554-Add-getMainThreadExecutor-to-BukkitScheduler.patch b/patches/server/0548-Add-getMainThreadExecutor-to-BukkitScheduler.patch similarity index 100% rename from patches/server/0554-Add-getMainThreadExecutor-to-BukkitScheduler.patch rename to patches/server/0548-Add-getMainThreadExecutor-to-BukkitScheduler.patch diff --git a/patches/server/0555-living-entity-allow-attribute-registration.patch b/patches/server/0549-living-entity-allow-attribute-registration.patch similarity index 100% rename from patches/server/0555-living-entity-allow-attribute-registration.patch rename to patches/server/0549-living-entity-allow-attribute-registration.patch diff --git a/patches/server/0556-fix-dead-slime-setSize-invincibility.patch b/patches/server/0550-fix-dead-slime-setSize-invincibility.patch similarity index 100% rename from patches/server/0556-fix-dead-slime-setSize-invincibility.patch rename to patches/server/0550-fix-dead-slime-setSize-invincibility.patch diff --git a/patches/server/0557-Merchant-getRecipes-should-return-an-immutable-list.patch b/patches/server/0551-Merchant-getRecipes-should-return-an-immutable-list.patch similarity index 100% rename from patches/server/0557-Merchant-getRecipes-should-return-an-immutable-list.patch rename to patches/server/0551-Merchant-getRecipes-should-return-an-immutable-list.patch diff --git a/patches/server/0558-Add-support-for-hex-color-codes-in-console.patch b/patches/server/0552-Add-support-for-hex-color-codes-in-console.patch similarity index 100% rename from patches/server/0558-Add-support-for-hex-color-codes-in-console.patch rename to patches/server/0552-Add-support-for-hex-color-codes-in-console.patch diff --git a/patches/server/0559-Expose-Tracked-Players.patch b/patches/server/0553-Expose-Tracked-Players.patch similarity index 100% rename from patches/server/0559-Expose-Tracked-Players.patch rename to patches/server/0553-Expose-Tracked-Players.patch diff --git a/patches/server/0560-Remove-streams-from-SensorNearest.patch b/patches/server/0554-Remove-streams-from-SensorNearest.patch similarity index 100% rename from patches/server/0560-Remove-streams-from-SensorNearest.patch rename to patches/server/0554-Remove-streams-from-SensorNearest.patch diff --git a/patches/server/0561-Throw-proper-exception-on-empty-JsonList-file.patch b/patches/server/0555-Throw-proper-exception-on-empty-JsonList-file.patch similarity index 100% rename from patches/server/0561-Throw-proper-exception-on-empty-JsonList-file.patch rename to patches/server/0555-Throw-proper-exception-on-empty-JsonList-file.patch diff --git a/patches/server/0562-Improve-ServerGUI.patch b/patches/server/0556-Improve-ServerGUI.patch similarity index 100% rename from patches/server/0562-Improve-ServerGUI.patch rename to patches/server/0556-Improve-ServerGUI.patch diff --git a/patches/server/0563-fix-converting-txt-to-json-file.patch b/patches/server/0557-fix-converting-txt-to-json-file.patch similarity index 100% rename from patches/server/0563-fix-converting-txt-to-json-file.patch rename to patches/server/0557-fix-converting-txt-to-json-file.patch diff --git a/patches/server/0564-Add-worldborder-events.patch b/patches/server/0558-Add-worldborder-events.patch similarity index 100% rename from patches/server/0564-Add-worldborder-events.patch rename to patches/server/0558-Add-worldborder-events.patch diff --git a/patches/server/0565-added-PlayerNameEntityEvent.patch b/patches/server/0559-added-PlayerNameEntityEvent.patch similarity index 100% rename from patches/server/0565-added-PlayerNameEntityEvent.patch rename to patches/server/0559-added-PlayerNameEntityEvent.patch diff --git a/patches/server/0566-Prevent-grindstones-from-overstacking-items.patch b/patches/server/0560-Prevent-grindstones-from-overstacking-items.patch similarity index 100% rename from patches/server/0566-Prevent-grindstones-from-overstacking-items.patch rename to patches/server/0560-Prevent-grindstones-from-overstacking-items.patch diff --git a/patches/server/0567-Add-recipe-to-cook-events.patch b/patches/server/0561-Add-recipe-to-cook-events.patch similarity index 100% rename from patches/server/0567-Add-recipe-to-cook-events.patch rename to patches/server/0561-Add-recipe-to-cook-events.patch diff --git a/patches/server/0568-Add-Block-isValidTool.patch b/patches/server/0562-Add-Block-isValidTool.patch similarity index 100% rename from patches/server/0568-Add-Block-isValidTool.patch rename to patches/server/0562-Add-Block-isValidTool.patch diff --git a/patches/server/0569-Allow-using-signs-inside-spawn-protection.patch b/patches/server/0563-Allow-using-signs-inside-spawn-protection.patch similarity index 100% rename from patches/server/0569-Allow-using-signs-inside-spawn-protection.patch rename to patches/server/0563-Allow-using-signs-inside-spawn-protection.patch diff --git a/patches/server/0570-Expand-world-key-API.patch b/patches/server/0564-Expand-world-key-API.patch similarity index 100% rename from patches/server/0570-Expand-world-key-API.patch rename to patches/server/0564-Expand-world-key-API.patch diff --git a/patches/server/0571-Add-fast-alternative-constructor-for-Rotations.patch b/patches/server/0565-Add-fast-alternative-constructor-for-Rotations.patch similarity index 100% rename from patches/server/0571-Add-fast-alternative-constructor-for-Rotations.patch rename to patches/server/0565-Add-fast-alternative-constructor-for-Rotations.patch diff --git a/patches/server/0572-Item-Rarity-API.patch b/patches/server/0566-Item-Rarity-API.patch similarity index 100% rename from patches/server/0572-Item-Rarity-API.patch rename to patches/server/0566-Item-Rarity-API.patch diff --git a/patches/server/0573-copy-TESign-isEditable-from-snapshots.patch b/patches/server/0567-copy-TESign-isEditable-from-snapshots.patch similarity index 100% rename from patches/server/0573-copy-TESign-isEditable-from-snapshots.patch rename to patches/server/0567-copy-TESign-isEditable-from-snapshots.patch diff --git a/patches/server/0574-Drop-carried-item-when-player-has-disconnected.patch b/patches/server/0568-Drop-carried-item-when-player-has-disconnected.patch similarity index 100% rename from patches/server/0574-Drop-carried-item-when-player-has-disconnected.patch rename to patches/server/0568-Drop-carried-item-when-player-has-disconnected.patch diff --git a/patches/server/0575-forced-whitelist-use-configurable-kick-message.patch b/patches/server/0569-forced-whitelist-use-configurable-kick-message.patch similarity index 100% rename from patches/server/0575-forced-whitelist-use-configurable-kick-message.patch rename to patches/server/0569-forced-whitelist-use-configurable-kick-message.patch diff --git a/patches/server/0576-Don-t-ignore-result-of-PlayerEditBookEvent.patch b/patches/server/0570-Don-t-ignore-result-of-PlayerEditBookEvent.patch similarity index 100% rename from patches/server/0576-Don-t-ignore-result-of-PlayerEditBookEvent.patch rename to patches/server/0570-Don-t-ignore-result-of-PlayerEditBookEvent.patch diff --git a/patches/server/0577-Expose-protocol-version.patch b/patches/server/0571-Expose-protocol-version.patch similarity index 100% rename from patches/server/0577-Expose-protocol-version.patch rename to patches/server/0571-Expose-protocol-version.patch diff --git a/patches/server/0578-Enhance-console-tab-completions-for-brigadier-comman.patch b/patches/server/0572-Enhance-console-tab-completions-for-brigadier-comman.patch similarity index 100% rename from patches/server/0578-Enhance-console-tab-completions-for-brigadier-comman.patch rename to patches/server/0572-Enhance-console-tab-completions-for-brigadier-comman.patch diff --git a/patches/server/0579-Fix-PlayerItemConsumeEvent-cancelling-properly.patch b/patches/server/0573-Fix-PlayerItemConsumeEvent-cancelling-properly.patch similarity index 100% rename from patches/server/0579-Fix-PlayerItemConsumeEvent-cancelling-properly.patch rename to patches/server/0573-Fix-PlayerItemConsumeEvent-cancelling-properly.patch diff --git a/patches/server/0580-Add-bypass-host-check.patch b/patches/server/0574-Add-bypass-host-check.patch similarity index 100% rename from patches/server/0580-Add-bypass-host-check.patch rename to patches/server/0574-Add-bypass-host-check.patch diff --git a/patches/server/0581-Set-area-affect-cloud-rotation.patch b/patches/server/0575-Set-area-affect-cloud-rotation.patch similarity index 100% rename from patches/server/0581-Set-area-affect-cloud-rotation.patch rename to patches/server/0575-Set-area-affect-cloud-rotation.patch diff --git a/patches/server/0582-add-isDeeplySleeping-to-HumanEntity.patch b/patches/server/0576-add-isDeeplySleeping-to-HumanEntity.patch similarity index 100% rename from patches/server/0582-add-isDeeplySleeping-to-HumanEntity.patch rename to patches/server/0576-add-isDeeplySleeping-to-HumanEntity.patch diff --git a/patches/server/0583-add-consumeFuel-to-FurnaceBurnEvent.patch b/patches/server/0577-add-consumeFuel-to-FurnaceBurnEvent.patch similarity index 100% rename from patches/server/0583-add-consumeFuel-to-FurnaceBurnEvent.patch rename to patches/server/0577-add-consumeFuel-to-FurnaceBurnEvent.patch diff --git a/patches/server/0584-add-get-set-drop-chance-to-EntityEquipment.patch b/patches/server/0578-add-get-set-drop-chance-to-EntityEquipment.patch similarity index 100% rename from patches/server/0584-add-get-set-drop-chance-to-EntityEquipment.patch rename to patches/server/0578-add-get-set-drop-chance-to-EntityEquipment.patch diff --git a/patches/server/0585-fix-PigZombieAngerEvent-cancellation.patch b/patches/server/0579-fix-PigZombieAngerEvent-cancellation.patch similarity index 100% rename from patches/server/0585-fix-PigZombieAngerEvent-cancellation.patch rename to patches/server/0579-fix-PigZombieAngerEvent-cancellation.patch diff --git a/patches/server/0586-fix-PlayerItemHeldEvent-firing-twice.patch b/patches/server/0580-fix-PlayerItemHeldEvent-firing-twice.patch similarity index 100% rename from patches/server/0586-fix-PlayerItemHeldEvent-firing-twice.patch rename to patches/server/0580-fix-PlayerItemHeldEvent-firing-twice.patch diff --git a/patches/server/0587-Added-PlayerDeepSleepEvent.patch b/patches/server/0581-Added-PlayerDeepSleepEvent.patch similarity index 100% rename from patches/server/0587-Added-PlayerDeepSleepEvent.patch rename to patches/server/0581-Added-PlayerDeepSleepEvent.patch diff --git a/patches/server/0588-More-World-API.patch b/patches/server/0582-More-World-API.patch similarity index 100% rename from patches/server/0588-More-World-API.patch rename to patches/server/0582-More-World-API.patch diff --git a/patches/server/0589-Added-PlayerBedFailEnterEvent.patch b/patches/server/0583-Added-PlayerBedFailEnterEvent.patch similarity index 100% rename from patches/server/0589-Added-PlayerBedFailEnterEvent.patch rename to patches/server/0583-Added-PlayerBedFailEnterEvent.patch diff --git a/patches/server/0590-Implement-methods-to-convert-between-Component-and-B.patch b/patches/server/0584-Implement-methods-to-convert-between-Component-and-B.patch similarity index 100% rename from patches/server/0590-Implement-methods-to-convert-between-Component-and-B.patch rename to patches/server/0584-Implement-methods-to-convert-between-Component-and-B.patch diff --git a/patches/server/0591-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch b/patches/server/0585-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch similarity index 100% rename from patches/server/0591-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch rename to patches/server/0585-Fix-anchor-respawn-acting-as-a-bed-respawn-from-the-.patch diff --git a/patches/server/0592-Introduce-beacon-activation-deactivation-events.patch b/patches/server/0586-Introduce-beacon-activation-deactivation-events.patch similarity index 100% rename from patches/server/0592-Introduce-beacon-activation-deactivation-events.patch rename to patches/server/0586-Introduce-beacon-activation-deactivation-events.patch diff --git a/patches/server/0593-add-RespawnFlags-to-PlayerRespawnEvent.patch b/patches/server/0587-add-RespawnFlags-to-PlayerRespawnEvent.patch similarity index 100% rename from patches/server/0593-add-RespawnFlags-to-PlayerRespawnEvent.patch rename to patches/server/0587-add-RespawnFlags-to-PlayerRespawnEvent.patch diff --git a/patches/server/0594-Add-Channel-initialization-listeners.patch b/patches/server/0588-Add-Channel-initialization-listeners.patch similarity index 100% rename from patches/server/0594-Add-Channel-initialization-listeners.patch rename to patches/server/0588-Add-Channel-initialization-listeners.patch diff --git a/patches/server/0595-Send-empty-commands-if-tab-completion-is-disabled.patch b/patches/server/0589-Send-empty-commands-if-tab-completion-is-disabled.patch similarity index 100% rename from patches/server/0595-Send-empty-commands-if-tab-completion-is-disabled.patch rename to patches/server/0589-Send-empty-commands-if-tab-completion-is-disabled.patch diff --git a/patches/server/0596-Add-more-WanderingTrader-API.patch b/patches/server/0590-Add-more-WanderingTrader-API.patch similarity index 100% rename from patches/server/0596-Add-more-WanderingTrader-API.patch rename to patches/server/0590-Add-more-WanderingTrader-API.patch diff --git a/patches/server/0597-Add-EntityBlockStorage-clearEntities.patch b/patches/server/0591-Add-EntityBlockStorage-clearEntities.patch similarity index 100% rename from patches/server/0597-Add-EntityBlockStorage-clearEntities.patch rename to patches/server/0591-Add-EntityBlockStorage-clearEntities.patch diff --git a/patches/server/0598-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch b/patches/server/0592-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch similarity index 100% rename from patches/server/0598-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch rename to patches/server/0592-Add-Adventure-message-to-PlayerAdvancementDoneEvent.patch diff --git a/patches/server/0599-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch b/patches/server/0593-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch similarity index 100% rename from patches/server/0599-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch rename to patches/server/0593-Add-raw-address-to-AsyncPlayerPreLoginEvent.patch diff --git a/patches/server/0600-Inventory-close.patch b/patches/server/0594-Inventory-close.patch similarity index 100% rename from patches/server/0600-Inventory-close.patch rename to patches/server/0594-Inventory-close.patch diff --git a/patches/server/0601-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch b/patches/server/0595-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch similarity index 100% rename from patches/server/0601-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch rename to patches/server/0595-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch diff --git a/patches/server/0602-Fix-CraftPotionBrewer-cache.patch b/patches/server/0596-Fix-CraftPotionBrewer-cache.patch similarity index 100% rename from patches/server/0602-Fix-CraftPotionBrewer-cache.patch rename to patches/server/0596-Fix-CraftPotionBrewer-cache.patch diff --git a/patches/server/0603-Add-basic-Datapack-API.patch b/patches/server/0597-Add-basic-Datapack-API.patch similarity index 100% rename from patches/server/0603-Add-basic-Datapack-API.patch rename to patches/server/0597-Add-basic-Datapack-API.patch diff --git a/patches/server/0604-Add-environment-variable-to-disable-server-gui.patch b/patches/server/0598-Add-environment-variable-to-disable-server-gui.patch similarity index 100% rename from patches/server/0604-Add-environment-variable-to-disable-server-gui.patch rename to patches/server/0598-Add-environment-variable-to-disable-server-gui.patch diff --git a/patches/server/0605-additions-to-PlayerGameModeChangeEvent.patch b/patches/server/0599-additions-to-PlayerGameModeChangeEvent.patch similarity index 100% rename from patches/server/0605-additions-to-PlayerGameModeChangeEvent.patch rename to patches/server/0599-additions-to-PlayerGameModeChangeEvent.patch diff --git a/patches/server/0606-ItemStack-repair-check-API.patch b/patches/server/0600-ItemStack-repair-check-API.patch similarity index 100% rename from patches/server/0606-ItemStack-repair-check-API.patch rename to patches/server/0600-ItemStack-repair-check-API.patch diff --git a/patches/server/0607-More-Enchantment-API.patch b/patches/server/0601-More-Enchantment-API.patch similarity index 100% rename from patches/server/0607-More-Enchantment-API.patch rename to patches/server/0601-More-Enchantment-API.patch diff --git a/patches/server/0608-Move-range-check-for-block-placing-up.patch b/patches/server/0602-Move-range-check-for-block-placing-up.patch similarity index 100% rename from patches/server/0608-Move-range-check-for-block-placing-up.patch rename to patches/server/0602-Move-range-check-for-block-placing-up.patch diff --git a/patches/server/0609-Fix-and-optimise-world-force-upgrading.patch b/patches/server/0603-Fix-and-optimise-world-force-upgrading.patch similarity index 100% rename from patches/server/0609-Fix-and-optimise-world-force-upgrading.patch rename to patches/server/0603-Fix-and-optimise-world-force-upgrading.patch diff --git a/patches/server/0610-Add-Mob-lookAt-API.patch b/patches/server/0604-Add-Mob-lookAt-API.patch similarity index 100% rename from patches/server/0610-Add-Mob-lookAt-API.patch rename to patches/server/0604-Add-Mob-lookAt-API.patch diff --git a/patches/server/0611-Add-Unix-domain-socket-support.patch b/patches/server/0605-Add-Unix-domain-socket-support.patch similarity index 100% rename from patches/server/0611-Add-Unix-domain-socket-support.patch rename to patches/server/0605-Add-Unix-domain-socket-support.patch diff --git a/patches/server/0612-Add-EntityInsideBlockEvent.patch b/patches/server/0606-Add-EntityInsideBlockEvent.patch similarity index 100% rename from patches/server/0612-Add-EntityInsideBlockEvent.patch rename to patches/server/0606-Add-EntityInsideBlockEvent.patch diff --git a/patches/server/0613-Attributes-API-for-item-defaults.patch b/patches/server/0607-Attributes-API-for-item-defaults.patch similarity index 100% rename from patches/server/0613-Attributes-API-for-item-defaults.patch rename to patches/server/0607-Attributes-API-for-item-defaults.patch diff --git a/patches/server/0614-Add-cause-to-Weather-ThunderChangeEvents.patch b/patches/server/0608-Add-cause-to-Weather-ThunderChangeEvents.patch similarity index 100% rename from patches/server/0614-Add-cause-to-Weather-ThunderChangeEvents.patch rename to patches/server/0608-Add-cause-to-Weather-ThunderChangeEvents.patch diff --git a/patches/server/0615-More-Lidded-Block-API.patch b/patches/server/0609-More-Lidded-Block-API.patch similarity index 100% rename from patches/server/0615-More-Lidded-Block-API.patch rename to patches/server/0609-More-Lidded-Block-API.patch diff --git a/patches/server/0616-Limit-item-frame-cursors-on-maps.patch b/patches/server/0610-Limit-item-frame-cursors-on-maps.patch similarity index 100% rename from patches/server/0616-Limit-item-frame-cursors-on-maps.patch rename to patches/server/0610-Limit-item-frame-cursors-on-maps.patch diff --git a/patches/server/0617-Add-PlayerKickEvent-causes.patch b/patches/server/0611-Add-PlayerKickEvent-causes.patch similarity index 100% rename from patches/server/0617-Add-PlayerKickEvent-causes.patch rename to patches/server/0611-Add-PlayerKickEvent-causes.patch diff --git a/patches/server/0618-Add-PufferFishStateChangeEvent.patch b/patches/server/0612-Add-PufferFishStateChangeEvent.patch similarity index 100% rename from patches/server/0618-Add-PufferFishStateChangeEvent.patch rename to patches/server/0612-Add-PufferFishStateChangeEvent.patch diff --git a/patches/server/0619-Fix-PlayerBucketEmptyEvent-result-itemstack.patch b/patches/server/0613-Fix-PlayerBucketEmptyEvent-result-itemstack.patch similarity index 100% rename from patches/server/0619-Fix-PlayerBucketEmptyEvent-result-itemstack.patch rename to patches/server/0613-Fix-PlayerBucketEmptyEvent-result-itemstack.patch diff --git a/patches/server/0620-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch b/patches/server/0614-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch similarity index 100% rename from patches/server/0620-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch rename to patches/server/0614-Synchronize-PalettedContainer-instead-of-ThreadingDe.patch diff --git a/patches/server/0621-Add-option-to-fix-items-merging-through-walls.patch b/patches/server/0615-Add-option-to-fix-items-merging-through-walls.patch similarity index 100% rename from patches/server/0621-Add-option-to-fix-items-merging-through-walls.patch rename to patches/server/0615-Add-option-to-fix-items-merging-through-walls.patch diff --git a/patches/server/0622-Add-BellRevealRaiderEvent.patch b/patches/server/0616-Add-BellRevealRaiderEvent.patch similarity index 100% rename from patches/server/0622-Add-BellRevealRaiderEvent.patch rename to patches/server/0616-Add-BellRevealRaiderEvent.patch diff --git a/patches/server/0623-Fix-invulnerable-end-crystals.patch b/patches/server/0617-Fix-invulnerable-end-crystals.patch similarity index 100% rename from patches/server/0623-Fix-invulnerable-end-crystals.patch rename to patches/server/0617-Fix-invulnerable-end-crystals.patch diff --git a/patches/server/0624-Add-ElderGuardianAppearanceEvent.patch b/patches/server/0618-Add-ElderGuardianAppearanceEvent.patch similarity index 100% rename from patches/server/0624-Add-ElderGuardianAppearanceEvent.patch rename to patches/server/0618-Add-ElderGuardianAppearanceEvent.patch diff --git a/patches/server/0625-Fix-dangerous-end-portal-logic.patch b/patches/server/0619-Fix-dangerous-end-portal-logic.patch similarity index 100% rename from patches/server/0625-Fix-dangerous-end-portal-logic.patch rename to patches/server/0619-Fix-dangerous-end-portal-logic.patch diff --git a/patches/server/0626-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch b/patches/server/0620-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch similarity index 100% rename from patches/server/0626-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch rename to patches/server/0620-Optimize-Biome-Mob-Lookups-for-Mob-Spawning.patch diff --git a/patches/server/0627-Make-item-validations-configurable.patch b/patches/server/0621-Make-item-validations-configurable.patch similarity index 100% rename from patches/server/0627-Make-item-validations-configurable.patch rename to patches/server/0621-Make-item-validations-configurable.patch diff --git a/patches/server/0628-Line-Of-Sight-Changes.patch b/patches/server/0622-Line-Of-Sight-Changes.patch similarity index 100% rename from patches/server/0628-Line-Of-Sight-Changes.patch rename to patches/server/0622-Line-Of-Sight-Changes.patch diff --git a/patches/server/0629-add-per-world-spawn-limits.patch b/patches/server/0623-add-per-world-spawn-limits.patch similarity index 100% rename from patches/server/0629-add-per-world-spawn-limits.patch rename to patches/server/0623-add-per-world-spawn-limits.patch diff --git a/patches/server/0630-Fix-potions-splash-events.patch b/patches/server/0624-Fix-potions-splash-events.patch similarity index 100% rename from patches/server/0630-Fix-potions-splash-events.patch rename to patches/server/0624-Fix-potions-splash-events.patch diff --git a/patches/server/0631-Add-more-LimitedRegion-API.patch b/patches/server/0625-Add-more-LimitedRegion-API.patch similarity index 100% rename from patches/server/0631-Add-more-LimitedRegion-API.patch rename to patches/server/0625-Add-more-LimitedRegion-API.patch diff --git a/patches/server/0632-Fix-PlayerDropItemEvent-using-wrong-item.patch b/patches/server/0626-Fix-PlayerDropItemEvent-using-wrong-item.patch similarity index 100% rename from patches/server/0632-Fix-PlayerDropItemEvent-using-wrong-item.patch rename to patches/server/0626-Fix-PlayerDropItemEvent-using-wrong-item.patch diff --git a/patches/server/0633-Missing-Entity-Behavior-API.patch b/patches/server/0627-Missing-Entity-Behavior-API.patch similarity index 100% rename from patches/server/0633-Missing-Entity-Behavior-API.patch rename to patches/server/0627-Missing-Entity-Behavior-API.patch diff --git a/patches/server/0634-Ensure-disconnect-for-book-edit-is-called-on-main.patch b/patches/server/0628-Ensure-disconnect-for-book-edit-is-called-on-main.patch similarity index 100% rename from patches/server/0634-Ensure-disconnect-for-book-edit-is-called-on-main.patch rename to patches/server/0628-Ensure-disconnect-for-book-edit-is-called-on-main.patch diff --git a/patches/server/0635-Fix-return-value-of-Block-applyBoneMeal-always-being.patch b/patches/server/0629-Fix-return-value-of-Block-applyBoneMeal-always-being.patch similarity index 100% rename from patches/server/0635-Fix-return-value-of-Block-applyBoneMeal-always-being.patch rename to patches/server/0629-Fix-return-value-of-Block-applyBoneMeal-always-being.patch diff --git a/patches/server/0636-Use-getChunkIfLoadedImmediately-in-places.patch b/patches/server/0630-Use-getChunkIfLoadedImmediately-in-places.patch similarity index 100% rename from patches/server/0636-Use-getChunkIfLoadedImmediately-in-places.patch rename to patches/server/0630-Use-getChunkIfLoadedImmediately-in-places.patch diff --git a/patches/server/0637-Fix-commands-from-signs-not-firing-command-events.patch b/patches/server/0631-Fix-commands-from-signs-not-firing-command-events.patch similarity index 100% rename from patches/server/0637-Fix-commands-from-signs-not-firing-command-events.patch rename to patches/server/0631-Fix-commands-from-signs-not-firing-command-events.patch diff --git a/patches/server/0638-Adds-PlayerArmSwingEvent.patch b/patches/server/0632-Adds-PlayerArmSwingEvent.patch similarity index 100% rename from patches/server/0638-Adds-PlayerArmSwingEvent.patch rename to patches/server/0632-Adds-PlayerArmSwingEvent.patch diff --git a/patches/server/0639-Fixes-kick-event-leave-message-not-being-sent.patch b/patches/server/0633-Fixes-kick-event-leave-message-not-being-sent.patch similarity index 100% rename from patches/server/0639-Fixes-kick-event-leave-message-not-being-sent.patch rename to patches/server/0633-Fixes-kick-event-leave-message-not-being-sent.patch diff --git a/patches/server/0640-Add-config-for-mobs-immune-to-default-effects.patch b/patches/server/0634-Add-config-for-mobs-immune-to-default-effects.patch similarity index 100% rename from patches/server/0640-Add-config-for-mobs-immune-to-default-effects.patch rename to patches/server/0634-Add-config-for-mobs-immune-to-default-effects.patch diff --git a/patches/server/0641-Fix-incorrect-message-for-outdated-client.patch b/patches/server/0635-Fix-incorrect-message-for-outdated-client.patch similarity index 100% rename from patches/server/0641-Fix-incorrect-message-for-outdated-client.patch rename to patches/server/0635-Fix-incorrect-message-for-outdated-client.patch diff --git a/patches/server/0642-Don-t-apply-cramming-damage-to-players.patch b/patches/server/0636-Don-t-apply-cramming-damage-to-players.patch similarity index 100% rename from patches/server/0642-Don-t-apply-cramming-damage-to-players.patch rename to patches/server/0636-Don-t-apply-cramming-damage-to-players.patch diff --git a/patches/server/0643-Rate-options-and-timings-for-sensors-and-behaviors.patch b/patches/server/0637-Rate-options-and-timings-for-sensors-and-behaviors.patch similarity index 100% rename from patches/server/0643-Rate-options-and-timings-for-sensors-and-behaviors.patch rename to patches/server/0637-Rate-options-and-timings-for-sensors-and-behaviors.patch diff --git a/patches/server/0644-Add-a-bunch-of-missing-forceDrop-toggles.patch b/patches/server/0638-Add-a-bunch-of-missing-forceDrop-toggles.patch similarity index 100% rename from patches/server/0644-Add-a-bunch-of-missing-forceDrop-toggles.patch rename to patches/server/0638-Add-a-bunch-of-missing-forceDrop-toggles.patch diff --git a/patches/server/0645-Stinger-API.patch b/patches/server/0639-Stinger-API.patch similarity index 100% rename from patches/server/0645-Stinger-API.patch rename to patches/server/0639-Stinger-API.patch diff --git a/patches/server/0646-Fix-incosistency-issue-with-empty-map-items-in-CB.patch b/patches/server/0640-Fix-incosistency-issue-with-empty-map-items-in-CB.patch similarity index 100% rename from patches/server/0646-Fix-incosistency-issue-with-empty-map-items-in-CB.patch rename to patches/server/0640-Fix-incosistency-issue-with-empty-map-items-in-CB.patch diff --git a/patches/server/0647-Add-System.out-err-catcher.patch b/patches/server/0641-Add-System.out-err-catcher.patch similarity index 100% rename from patches/server/0647-Add-System.out-err-catcher.patch rename to patches/server/0641-Add-System.out-err-catcher.patch diff --git a/patches/server/0648-Fix-test-not-bootstrapping.patch b/patches/server/0642-Fix-test-not-bootstrapping.patch similarity index 100% rename from patches/server/0648-Fix-test-not-bootstrapping.patch rename to patches/server/0642-Fix-test-not-bootstrapping.patch diff --git a/patches/server/0649-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch b/patches/server/0643-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch similarity index 100% rename from patches/server/0649-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch rename to patches/server/0643-Rewrite-LogEvents-to-contain-the-source-jars-in-stac.patch diff --git a/patches/server/0650-Improve-boat-collision-performance.patch b/patches/server/0644-Improve-boat-collision-performance.patch similarity index 100% rename from patches/server/0650-Improve-boat-collision-performance.patch rename to patches/server/0644-Improve-boat-collision-performance.patch diff --git a/patches/server/0651-Prevent-AFK-kick-while-watching-end-credits.patch b/patches/server/0645-Prevent-AFK-kick-while-watching-end-credits.patch similarity index 100% rename from patches/server/0651-Prevent-AFK-kick-while-watching-end-credits.patch rename to patches/server/0645-Prevent-AFK-kick-while-watching-end-credits.patch diff --git a/patches/server/0652-Add-PlayerSetSpawnEvent.patch b/patches/server/0646-Add-PlayerSetSpawnEvent.patch similarity index 100% rename from patches/server/0652-Add-PlayerSetSpawnEvent.patch rename to patches/server/0646-Add-PlayerSetSpawnEvent.patch diff --git a/patches/server/0653-Make-hoppers-respect-inventory-max-stack-size.patch b/patches/server/0647-Make-hoppers-respect-inventory-max-stack-size.patch similarity index 100% rename from patches/server/0653-Make-hoppers-respect-inventory-max-stack-size.patch rename to patches/server/0647-Make-hoppers-respect-inventory-max-stack-size.patch diff --git a/patches/server/0654-Optimize-entity-tracker-passenger-checks.patch b/patches/server/0648-Optimize-entity-tracker-passenger-checks.patch similarity index 100% rename from patches/server/0654-Optimize-entity-tracker-passenger-checks.patch rename to patches/server/0648-Optimize-entity-tracker-passenger-checks.patch diff --git a/patches/server/0655-Config-option-for-Piglins-guarding-chests.patch b/patches/server/0649-Config-option-for-Piglins-guarding-chests.patch similarity index 100% rename from patches/server/0655-Config-option-for-Piglins-guarding-chests.patch rename to patches/server/0649-Config-option-for-Piglins-guarding-chests.patch diff --git a/patches/server/0656-Added-EntityDamageItemEvent.patch b/patches/server/0650-Added-EntityDamageItemEvent.patch similarity index 100% rename from patches/server/0656-Added-EntityDamageItemEvent.patch rename to patches/server/0650-Added-EntityDamageItemEvent.patch diff --git a/patches/server/0657-Optimize-indirect-passenger-iteration.patch b/patches/server/0651-Optimize-indirect-passenger-iteration.patch similarity index 100% rename from patches/server/0657-Optimize-indirect-passenger-iteration.patch rename to patches/server/0651-Optimize-indirect-passenger-iteration.patch diff --git a/patches/server/0658-Configurable-item-frame-map-cursor-update-interval.patch b/patches/server/0652-Configurable-item-frame-map-cursor-update-interval.patch similarity index 100% rename from patches/server/0658-Configurable-item-frame-map-cursor-update-interval.patch rename to patches/server/0652-Configurable-item-frame-map-cursor-update-interval.patch diff --git a/patches/server/0659-Make-EntityUnleashEvent-cancellable.patch b/patches/server/0653-Make-EntityUnleashEvent-cancellable.patch similarity index 100% rename from patches/server/0659-Make-EntityUnleashEvent-cancellable.patch rename to patches/server/0653-Make-EntityUnleashEvent-cancellable.patch diff --git a/patches/server/0660-Clear-bucket-NBT-after-dispense.patch b/patches/server/0654-Clear-bucket-NBT-after-dispense.patch similarity index 100% rename from patches/server/0660-Clear-bucket-NBT-after-dispense.patch rename to patches/server/0654-Clear-bucket-NBT-after-dispense.patch diff --git a/patches/server/0661-Change-EnderEye-target-without-changing-other-things.patch b/patches/server/0655-Change-EnderEye-target-without-changing-other-things.patch similarity index 100% rename from patches/server/0661-Change-EnderEye-target-without-changing-other-things.patch rename to patches/server/0655-Change-EnderEye-target-without-changing-other-things.patch diff --git a/patches/server/0662-Add-BlockBreakBlockEvent.patch b/patches/server/0656-Add-BlockBreakBlockEvent.patch similarity index 100% rename from patches/server/0662-Add-BlockBreakBlockEvent.patch rename to patches/server/0656-Add-BlockBreakBlockEvent.patch diff --git a/patches/server/0663-Option-to-prevent-NBT-copy-in-smithing-recipes.patch b/patches/server/0657-Option-to-prevent-NBT-copy-in-smithing-recipes.patch similarity index 100% rename from patches/server/0663-Option-to-prevent-NBT-copy-in-smithing-recipes.patch rename to patches/server/0657-Option-to-prevent-NBT-copy-in-smithing-recipes.patch diff --git a/patches/server/0664-More-CommandBlock-API.patch b/patches/server/0658-More-CommandBlock-API.patch similarity index 100% rename from patches/server/0664-More-CommandBlock-API.patch rename to patches/server/0658-More-CommandBlock-API.patch diff --git a/patches/server/0665-Add-missing-team-sidebar-display-slots.patch b/patches/server/0659-Add-missing-team-sidebar-display-slots.patch similarity index 100% rename from patches/server/0665-Add-missing-team-sidebar-display-slots.patch rename to patches/server/0659-Add-missing-team-sidebar-display-slots.patch diff --git a/patches/server/0666-Add-back-EntityPortalExitEvent.patch b/patches/server/0660-Add-back-EntityPortalExitEvent.patch similarity index 100% rename from patches/server/0666-Add-back-EntityPortalExitEvent.patch rename to patches/server/0660-Add-back-EntityPortalExitEvent.patch diff --git a/patches/server/0667-Add-methods-to-find-targets-for-lightning-strikes.patch b/patches/server/0661-Add-methods-to-find-targets-for-lightning-strikes.patch similarity index 100% rename from patches/server/0667-Add-methods-to-find-targets-for-lightning-strikes.patch rename to patches/server/0661-Add-methods-to-find-targets-for-lightning-strikes.patch diff --git a/patches/server/0668-Get-entity-default-attributes.patch b/patches/server/0662-Get-entity-default-attributes.patch similarity index 100% rename from patches/server/0668-Get-entity-default-attributes.patch rename to patches/server/0662-Get-entity-default-attributes.patch diff --git a/patches/server/0669-Left-handed-API.patch b/patches/server/0663-Left-handed-API.patch similarity index 100% rename from patches/server/0669-Left-handed-API.patch rename to patches/server/0663-Left-handed-API.patch diff --git a/patches/server/0670-Add-more-advancement-API.patch b/patches/server/0664-Add-more-advancement-API.patch similarity index 100% rename from patches/server/0670-Add-more-advancement-API.patch rename to patches/server/0664-Add-more-advancement-API.patch diff --git a/patches/server/0671-Add-ItemFactory-getSpawnEgg-API.patch b/patches/server/0665-Add-ItemFactory-getSpawnEgg-API.patch similarity index 100% rename from patches/server/0671-Add-ItemFactory-getSpawnEgg-API.patch rename to patches/server/0665-Add-ItemFactory-getSpawnEgg-API.patch diff --git a/patches/server/0672-Add-critical-damage-API.patch b/patches/server/0666-Add-critical-damage-API.patch similarity index 100% rename from patches/server/0672-Add-critical-damage-API.patch rename to patches/server/0666-Add-critical-damage-API.patch diff --git a/patches/server/0673-Fix-issues-with-mob-conversion.patch b/patches/server/0667-Fix-issues-with-mob-conversion.patch similarity index 100% rename from patches/server/0673-Fix-issues-with-mob-conversion.patch rename to patches/server/0667-Fix-issues-with-mob-conversion.patch diff --git a/patches/server/0674-Add-isCollidable-methods-to-various-places.patch b/patches/server/0668-Add-isCollidable-methods-to-various-places.patch similarity index 100% rename from patches/server/0674-Add-isCollidable-methods-to-various-places.patch rename to patches/server/0668-Add-isCollidable-methods-to-various-places.patch diff --git a/patches/server/0675-Goat-ram-API.patch b/patches/server/0669-Goat-ram-API.patch similarity index 100% rename from patches/server/0675-Goat-ram-API.patch rename to patches/server/0669-Goat-ram-API.patch diff --git a/patches/server/0676-Add-API-for-resetting-a-single-score.patch b/patches/server/0670-Add-API-for-resetting-a-single-score.patch similarity index 100% rename from patches/server/0676-Add-API-for-resetting-a-single-score.patch rename to patches/server/0670-Add-API-for-resetting-a-single-score.patch diff --git a/patches/server/0677-Add-Raw-Byte-Entity-Serialization.patch b/patches/server/0671-Add-Raw-Byte-Entity-Serialization.patch similarity index 100% rename from patches/server/0677-Add-Raw-Byte-Entity-Serialization.patch rename to patches/server/0671-Add-Raw-Byte-Entity-Serialization.patch diff --git a/patches/server/0678-Vanilla-command-permission-fixes.patch b/patches/server/0672-Vanilla-command-permission-fixes.patch similarity index 100% rename from patches/server/0678-Vanilla-command-permission-fixes.patch rename to patches/server/0672-Vanilla-command-permission-fixes.patch diff --git a/patches/server/0679-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch b/patches/server/0673-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch similarity index 100% rename from patches/server/0679-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch rename to patches/server/0673-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch diff --git a/patches/server/0680-Fix-GameProfileCache-concurrency.patch b/patches/server/0674-Fix-GameProfileCache-concurrency.patch similarity index 100% rename from patches/server/0680-Fix-GameProfileCache-concurrency.patch rename to patches/server/0674-Fix-GameProfileCache-concurrency.patch diff --git a/patches/server/0681-Improve-and-expand-AsyncCatcher.patch b/patches/server/0675-Improve-and-expand-AsyncCatcher.patch similarity index 100% rename from patches/server/0681-Improve-and-expand-AsyncCatcher.patch rename to patches/server/0675-Improve-and-expand-AsyncCatcher.patch diff --git a/patches/server/0682-Add-paper-mobcaps-and-paper-playermobcaps.patch b/patches/server/0676-Add-paper-mobcaps-and-paper-playermobcaps.patch similarity index 100% rename from patches/server/0682-Add-paper-mobcaps-and-paper-playermobcaps.patch rename to patches/server/0676-Add-paper-mobcaps-and-paper-playermobcaps.patch diff --git a/patches/server/0683-Sanitize-ResourceLocation-error-logging.patch b/patches/server/0677-Sanitize-ResourceLocation-error-logging.patch similarity index 100% rename from patches/server/0683-Sanitize-ResourceLocation-error-logging.patch rename to patches/server/0677-Sanitize-ResourceLocation-error-logging.patch diff --git a/patches/server/0684-Optimise-general-POI-access.patch b/patches/server/0678-Optimise-general-POI-access.patch similarity index 100% rename from patches/server/0684-Optimise-general-POI-access.patch rename to patches/server/0678-Optimise-general-POI-access.patch